Load data files
library(dplyr)
# specify the directory where the files are located
# For NOAA machines
# dir_path <- "/Users/enrique.montes/Google Drive/My Drive/GDrive/OCED_AOML/WS_cruises/plankton_imaging/CPICS/TS.Master_selection"
# For personal machine
dir_path <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/OCED_AOML/WS_cruises/plankton_imaging/CPICS/TS.Master_selection"
# obtain a list of file names in the directory
file_names <- list.files(path = dir_path, pattern = ".txt", full.names = TRUE)
# loop over each file and import the tables (use this for DATES)
for (file in file_names) {
table_name <- gsub(".txt", "", basename(file)) # get the name of the table from the file name
assign(table_name, read.table(file = file, header = FALSE, sep = "\t") %>%
mutate(date = as.POSIXct(substr(V1, start = 24, stop = 36), format="%Y%m%d_%H%M", tz="UTC")))
}
# # loop over each file and import the tables (use this for STRINGS)
# for (file in file_names) {
# table_name <- gsub(".txt", "", basename(file)) # get the name of the table from the file name
# assign(table_name, read.table(file = file, header = FALSE, sep = "\t"))
# }
Match file name using DATE values
library(tidyverse)
library(lubridate)
dir_path2 <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/OCED_AOML/WS_cruises/plankton_imaging/CPICS/ws_cruise_ctd"
file_name <- list.files(path = dir_path2, pattern = "ctd_meta_v3.csv", full.names = TRUE)
ctd_meta <- read.csv(file_name, fill = TRUE)
# USE WITH ctd_meta_v3.csv
dt_list <- as.POSIXct(paste(ctd_meta$year,
sprintf("%02d", ctd_meta$month),
sprintf("%02d", ctd_meta$day),
ctd_meta$time_gmt),
format = "%Y%m%d %I:%M:%S %p",
tz = "UTC")
################################################################################################################
# This section detects short transit times between stations
# Calculate time differences in seconds between consecutive dt_list objects
time_differences <- as.numeric(difftime(dt_list[-1], dt_list[-length(dt_list)], units = "secs"))
# Convert time differences from seconds to minutes
time_differences_mins <- time_differences / 60
# Create a data frame showing the original times and their differences in minutes
time_diff_df <- data.frame(
start_time = dt_list[-length(dt_list)],
end_time = dt_list[-1],
time_difference_mins = time_differences_mins
)
# find CTD time stamps of consecutive stations within less than 20 min. This will identify CTD casts that are close to each other
short_t_idx <- which(time_diff_df$time_difference_mins < 20)
short_timestamps <- dt_list[short_t_idx]
#################################################################################################################
# Create empty data frame to store results
conc_occ_final <- data.frame(date = character(), count = numeric())
# List of class objects to be processed
class_names <- c("Acantharea", "Centric", "Ceratium", "Chaetoceros", "Chaetognaths",
"Chain2", "Chain3", "Ostracods", "Copepods", "Decapods", "Echinoderms",
"Guinardia", "Jellies", "Larvaceans", "Neocalyptrella", "Noctiluca",
"pellets", "Polychaets", "Pteropods", "Tricho")
# time buffer before and after CTD time in seconds so that CPICS records are matched to CTD times.
start <- 10 * 60
stop <- 10 * 60
# Iterate over dt_list intervals
for (i in 1:length(dt_list)) {
# Initialize a list to store counts for the current interval
counts_list <- list(date = dt_list[i])
# Iterate over each class object and perform subsetting
for (class_name in class_names) {
class_data <- get(paste0("class.", class_name)) # Dynamically get the class data frame
if (i < length(dt_list)) {
# Subsetting for all intervals except the last one
subset_data <- subset(class_data, date >= dt_list[i]-start & date < dt_list[i+1]-stop)
} else {
# Subsetting for the last interval: capture all data greater than or equal to the last dt_list
subset_data <- subset(class_data, date >= dt_list[i]-start)
}
counts_list[[class_name]] <- nrow(subset_data)
}
# Convert counts_list to a data frame and bind it to the result
result <- as.data.frame(counts_list)
conc_occ_final <- rbind(conc_occ_final, result)
}
# Combine with ctd_meta
taxa_meta <- cbind(ctd_meta, conc_occ_final)
################################################################################
# Check for unaccounted CPICS records
# Initialize a list to store unaccounted dates for each class
unaccounted_dates_list <- list()
# Iterate over each class object
for (class_name in class_names) {
# Get the date-time objects from the current class
sel_class_dates <- get(paste0("class.", class_name))$date
# Initialize a logical vector to track whether each class date is accounted for
is_accounted_for <- rep(FALSE, length(sel_class_dates))
# Check each class date against the intervals in dt_list
for (i in 1:length(dt_list)) {
if (i < length(dt_list)) {
# Check all intervals except the last one
interval_start <- dt_list[i] - start
interval_end <- dt_list[i + 1] - stop
} else {
# Last interval captures all data greater than or equal to the last dt_list
interval_start <- dt_list[i] - start
interval_end <- Inf # Effectively no upper bound
}
# Mark class dates that fall within the current interval as accounted for
is_accounted_for <- is_accounted_for | (sel_class_dates >= interval_start & sel_class_dates < interval_end)
}
# Subset the class dates that were not accounted for
unaccounted_sel_class_dates <- sel_class_dates[!is_accounted_for]
# Store the unaccounted dates in the list
unaccounted_dates_list[[class_name]] <- unaccounted_sel_class_dates
}
# Print or view the unaccounted dates for each class
for (class_name in class_names) {
cat("Unaccounted dates for class:", class_name, "\n")
print(unaccounted_dates_list[[class_name]])
cat("\n")
}
Unaccounted dates for class: Acantharea
POSIXct of length 0
Unaccounted dates for class: Centric
POSIXct of length 0
Unaccounted dates for class: Ceratium
POSIXct of length 0
Unaccounted dates for class: Chaetoceros
POSIXct of length 0
Unaccounted dates for class: Chaetognaths
POSIXct of length 0
Unaccounted dates for class: Chain2
POSIXct of length 0
Unaccounted dates for class: Chain3
POSIXct of length 0
Unaccounted dates for class: Ostracods
POSIXct of length 0
Unaccounted dates for class: Copepods
POSIXct of length 0
Unaccounted dates for class: Decapods
POSIXct of length 0
Unaccounted dates for class: Echinoderms
POSIXct of length 0
Unaccounted dates for class: Guinardia
POSIXct of length 0
Unaccounted dates for class: Jellies
POSIXct of length 0
Unaccounted dates for class: Larvaceans
POSIXct of length 0
Unaccounted dates for class: Neocalyptrella
POSIXct of length 0
Unaccounted dates for class: Noctiluca
POSIXct of length 0
Unaccounted dates for class: pellets
POSIXct of length 0
Unaccounted dates for class: Polychaets
POSIXct of length 0
Unaccounted dates for class: Pteropods
POSIXct of length 0
Unaccounted dates for class: Tricho
POSIXct of length 0
# Calculate plankton concentration time series per station
# Calculate species concentration (counts/ml) for each species
# For zooplankton
taxa_meta_concentration <- taxa_meta %>%
mutate(across(c(Acantharea,Chaetognaths,Ostracods,Copepods,Decapods,Echinoderms,Jellies,
Larvaceans,Polychaets,Pteropods), ~ ./total_vol_sampled * 1e6)) %>%
select(Station, dec_lat, dec_lon, year, month, date, Avg.chl.a..ug.L.,
temp..degC., salinity, total_vol_sampled,
Acantharea,Chaetognaths,Ostracods,Copepods,Decapods,Echinoderms,
Jellies,Larvaceans,Polychaets,Pteropods) %>%
filter(!is.na(total_vol_sampled))
# # Transform taxa_meta_concentration to long format
taxa_meta_long <- taxa_meta_concentration %>%
pivot_longer(cols = c(Acantharea, Chaetognaths,Ostracods,Copepods,Decapods,
Echinoderms, Jellies, Larvaceans,Polychaets, Pteropods),
names_to = "species", values_to = "species_concentration")
# # For phytoplankton
# taxa_meta_concentration <- taxa_meta %>%
# mutate(across(c(Centric,Ceratium,Chaetoceros,Chain2,Chain3,Guinardia,Neocalyptrella,
# Noctiluca,Tricho), ~ ./total_vol_sampled * 1e6)) %>%
# select(Station, dec_lat, dec_lon, year, month, date, Avg.chl.a..ug.L.,
# temp..degC., salinity,total_vol_sampled,
# Centric,Ceratium,Chaetoceros,Chain2,Chain3,Guinardia,Neocalyptrella,
# Noctiluca,Tricho) %>%
# filter(!is.na(total_vol_sampled))
#
# # # Transform taxa_meta_concentration to long format
# taxa_meta_long <- taxa_meta_concentration %>%
# pivot_longer(cols = c(Centric,Ceratium,Chaetoceros,Chain2,Chain3,Guinardia,Neocalyptrella,
# Noctiluca,Tricho),
# names_to = "species", values_to = "species_concentration")
# Filter the data for Stations
# station_list_fk <- c("WS","21/LK","MR","16","18","10","12","9.5","9","7","2")
# station_list_sr <- c("68","65","64","60","58","57.3","57.2","57.1","57","56","55","54","53","51",
# "49","47","45","41","30","31","33")
# station_list_cal <- c("CAL5","CAL4","CAL3","CAL2","CAL1","RP1","RP2","RP3","RP4","GP5","BG4","BG3",
# "BG2","BG1","BG6", "BG7")
# station_list_vl <- c("V1","V2","V3","V4","V5","V6","V7","V8","V9","L1","L3","L5","L7","L9")
# station_list_tb <- c("AMI9","AMI8","AMI7","AMI6","AMI5","AMI4","AMI3","AMI2","AMI1","TB1","TB2",
# "TB3","TB4","TB5","TB10","CW4","CW3","CW2","CW1")
# filtered_taxa_meta_long <- taxa_meta_long %>%
# filter(Station %in% station_list_fk)
# Without filtering per group of stations but looking at the entire region
filtered_taxa_meta_long <- taxa_meta_long
# Calculate mean and standard deviation of species concentration for each date
summary_data <- filtered_taxa_meta_long %>%
group_by(year, month, species) %>%
summarise(mean_concentration = mean(species_concentration, na.rm = TRUE),
sd_concentration = sd(species_concentration, na.rm = TRUE),
earliest_day = min(as.numeric(format(date, "%d")), na.rm = TRUE)) %>%
ungroup()
`summarise()` has grouped output by 'year', 'month'. You can override using the `.groups` argument.
# Combine year and month columns into a single date column
summary_data$date <- as.Date(paste(summary_data$year, summary_data$month, summary_data$earliest_day, sep = "-"))
# custom_pal_hex2 <- c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf')
custom_pal_hex2 <- c('darkturquoise','red','#4daf4a','slategray4','orange','dodgerblue','purple', "yellow","pink","violet")
# Acantharea = darkturquoise
# Copepods = red
# echinos = #4daf4a
# Jellies = slategray4
# Larvaceans = orange
# Polychaetes = dodgerblue
# Pteropods = purple
# # Check dominance of groups by calculating the overall mean
# test <- summary_data %>% filter(species == "Polychaetes") %>% summarize(avg = mean(mean_concentration))
# mean(test$avg)
# Plot time series of mean+sd planton concentration per group of sites
zz <- ggplot(summary_data, aes(x = date, y = mean_concentration, fill = species)) +
geom_bar(stat = "identity", alpha = 0.7) +
scale_fill_manual(values = custom_pal_hex2) +
# geom_errorbar(aes(ymin = 0, ymax = mean_concentration + sd_concentration),
# position = position_dodge(width = 0.9), width = 0.2) +
labs(x = "Date", y = "Mean Species Concentration", fill = "Species") +
theme_minimal()
zz

# Filter summary_data for selected only
# Acantharea, Copepods, Echinoderms, Jellies, Larvaceans, Chaetognaths, Polychaetes, Pteropods
# Centric,Ceratium,Chaetoceros,Chain2,Chain2,Guinardia,Neocalyptrella,Noctiluca,Trichodesmium
selected_group <- "Pteropods"
summary_selected <- filtered_taxa_meta_long %>%
filter(species == selected_group) %>%
filter(species_concentration > 0) %>%
group_by(year, month) %>%
mutate(earliest_day = min(as.numeric(format(date, "%d")), na.rm = TRUE)) %>%
ungroup() %>%
mutate(date = as.Date(paste(year, month, earliest_day, sep = "-"))) %>%
select(-earliest_day) # Optionally, remove the 'earliest_day' column if not needed
# Create the time series boxplot
sel_box <- ggplot(summary_selected, aes(x = as.factor(date), y = species_concentration)) +
geom_boxplot(fill = "white", notch = FALSE, outlier.shape = NA) +
# geom_violin(fill = "lightgrey", color = "NA", alpha = 0.7) +
# geom_jitter(aes(color = factor(Station), size = temp..degC.), alpha = 0.9) +
# geom_jitter(width = 0.25, aes(color = temp..degC., size = salinity), alpha = 0.6) + # with salinity included
geom_jitter(width = 0.25, aes(color = temp..degC.), size = 3, alpha = 0.6) +
labs(x = "Date", y = expression("Density (org. m"^"-3"~")")) +
scale_color_viridis_c(name = "Temperature (°C)", option = "inferno") +
# scale_size_continuous(name = "Salinity", # with salinity included
# limits = c(30, 38),
# breaks = c(30, 32, 34, 36, 38),
# range = c(1, 4)) +
ylim(0, 30000) +
theme_minimal() +
theme(axis.text.x = element_text(size = 18, color = "black"), # Set X-axis label font size
axis.text.y = element_text(size = 18, color = "black")) +
theme(axis.title.x = element_text(size = 18, color = "black"),
axis.title.y = element_text(size = 18, color = "black")) +
theme(legend.text = element_text(size = 14)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
theme(axis.line = element_line(color = "black"))
sel_box
Warning: Removed 1 rows containing non-finite values (`stat_boxplot()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
# Save figure as a svg file
ggsave(paste0("conc_time-series_", selected_group, ".svg"), plot = sel_box, width = 10, height = 8, device = "svg")
Warning: Removed 1 rows containing non-finite values (`stat_boxplot()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).

# # Plot concentration time series for all selected sites
# kk <- ggplot(summary_selected, aes(x = date, y = species_concentration, shape = factor(Station))) +
# labs(x = "Date", y = "Species concentration (org.m-3)") +
# geom_point(aes(size = temp..degC.), fill = "darkgrey") + # or colour = factor(Station)
# scale_shape_manual(values = c(0, 1, 2, 3, 4, 5, 6))
# kk
# kk <- ggplot(summary_selected, aes(x = date, y = species_concentration, colour = factor(Station))) +
# labs(x = "Date", y = "Species concentration (org.m-3)") +
# geom_point(aes(size = temp..degC.), alpha = 0.7) + # or colour = factor(Station) +
# # geom_smooth(method = "lm", formula = y ~ poly(x, 4), se = FALSE) + # Add polynomial fit line
# scale_colour_brewer(palette = "Set1")
# kk
# # Find the index of the last row with date == '2023-01-15' and add a dummy row for missing dates
# new_row <- tibble(Station = NA, dec_lat = NA, dec_lon = NA, year = NA,
# month = NA, date = as.Date('2023-03-15'), Avg.chl.a..ug.L. = NA,
# temp..degC. = NA, salinity = NA, species = NA, species_concentration = NA)
# last_index <- max(which(summary_selected$date == as.Date('2023-01-15')))
# summary_selected <- bind_rows(
# summary_selected[1:last_index, ],
# new_row,
# summary_selected[(last_index + 1):nrow(summary_selected), ]
# )
# Calculates total plankton concentrations aggregating data from
selected stations (eg FK)
# Calculate plankton concentration for all species summed up
# For Phyto
taxa_meta_concentration_all <- taxa_meta %>%
mutate(total_concentration = (
Centric + Ceratium + Chaetoceros + Chain2 + Chain3 + Guinardia + Neocalyptrella +
Noctiluca + Tricho) / total_vol_sampled * 1e6) %>%
select(Station, dec_lat, dec_lon, year, month, date, Avg.chl.a..ug.L.,
temp..degC., salinity, total_vol_sampled, total_concentration) %>%
filter(!is.na(total_vol_sampled))
# # For Zooplankton
# taxa_meta_concentration_all <- taxa_meta %>%
# mutate(total_concentration = (
# Acantharea + Chaetognaths + Ostracods + Copepods + Decapods + Echinoderms + Jellies +
# Larvaceans + Polychaets + Pteropods) / total_vol_sampled * 1e6) %>%
# select(Station, dec_lat, dec_lon, year, month, date, Avg.chl.a..ug.L.,
# temp..degC., salinity, total_vol_sampled, total_concentration) %>%
# filter(!is.na(total_vol_sampled))
# Filter the data for Stations
station_list_fk <- c("WS","21/LK","MR","16","18","10","12","9.5","9","7","2")
filtered_taxa_conc_all <- taxa_meta_concentration_all %>%
filter(Station %in% station_list_fk)
# Aggregate total concentration and total volume sampled per year and month
aggregated_concentration <- filtered_taxa_conc_all %>%
group_by(year, month) %>%
summarise(
total_counts = sum(total_concentration * total_vol_sampled / 1e6, na.rm = TRUE), # Sum up all counts
total_vol_sampled = sum(total_vol_sampled, na.rm = TRUE), # Sum up all volume sampled
mean_temp_degC = mean(temp..degC., na.rm = TRUE), # Calculate mean temperature
mean_salinity = mean(salinity, na.rm = TRUE), # Calculate mean salinity
mean_chla = mean(Avg.chl.a..ug.L., na.rm = TRUE)
) %>%
ungroup() %>%
mutate(total_concentration = (total_counts / total_vol_sampled) * 1e6) # Recalculate the concentration
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.
# Create a Date column for plotting purposes
aggregated_concentration <- aggregated_concentration %>%
mutate(year_month = as.Date(paste(year, month, "01", sep = "-")))
# Create the time series plot
concentration_ts <- ggplot(aggregated_concentration, aes(x = year_month)) +
geom_line(aes(y = total_concentration), color = "blue", size = 1) + # Line plot for total concentration
geom_point(aes(y = total_concentration), color = "red", size = 2) + # Points for total concentration
# geom_line(aes(y = (mean_temp_degC - 20) / (35 - 20) * max(total_concentration)),
# color = "orange", size = 1) + # Line plot for temperature (normalized)
labs(title = "Total Phytoplankton Concentration Time Series",
x = "Date",
y = expression("Total Concentration (org/m"^3~")")) +
scale_x_date(date_breaks = "1 month", date_labels = "%b %Y") + # Show ticks for every month
scale_y_continuous(
name = expression("Total Concentration (org/m"^3~")"), # Primary y-axis label
# sec.axis = sec_axis(~ . * (35 - 20) / max(aggregated_concentration$total_concentration) + 20,
# name = "Temperature (°C)",
# breaks = seq(20, 35, by = 5)) # Secondary y-axis label
) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
# axis.title.y.right = element_text(color = "orange"), # Color the secondary y-axis label
# axis.line.y.right = element_line(color = "orange"), # Color the secondary y-axis line
# panel.grid.major = element_blank(), # Remove major grid lines
panel.grid.minor = element_blank(), # Remove minor grid lines
# panel.border = element_blank() # Remove panel border if necessary
)
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
# Print the plot
concentration_ts

# Calculate plankton concentrations per seascape class
spp_df <- taxa_meta[ , c("X8.day.seascapes", "total_vol_sampled", "date",
"Acantharea",
"Copepods",
"Echinoderms",
"Jellies",
"Larvaceans",
"Polychaets",
"Chaetognaths",
"Pteropods")]
# spp_df <- taxa_meta[ , c("X8.day.seascapes", "total_vol_sampled", "date",
# "Ceratium",
# "Chaetoceros",
# "Chain2",
# "Chain3",
# "Guinardia",
# "Neocalyptrella",
# "Tricho")]
# Remove rows with NaN values in X8.day.seascapes and total_vol_sampled
spp_df <- subset(spp_df, !is.na(X8.day.seascapes) & !is.na(total_vol_sampled))
# Calculate total counts per species within each X8.day.seascapes category
spp_count_per_seascape <- spp_df %>%
gather(key = "species", value = "count", -(X8.day.seascapes:date)) %>%
group_by(X8.day.seascapes, species) %>%
summarise(total_count = sum(count)) %>%
ungroup()
`summarise()` has grouped output by 'X8.day.seascapes'. You can override using the `.groups` argument.
# Calculate total volume sampled per X8.day.seascapes category
total_vol_per_seascape <- spp_df %>%
group_by(X8.day.seascapes) %>%
summarise(total_vol_sampled = sum(total_vol_sampled))
# Merge total counts and total volume data frames
spp_concentration <- merge(spp_count_per_seascape, total_vol_per_seascape, by = "X8.day.seascapes")
# Calculate species per cubic meter: might be misleading since it integrates all counts and sampled volumes across cruises to calculate concentrations. It is likely better to use average concentrations as below.
spp_concentration$species_per_cubic_meter <- spp_concentration$total_count / spp_concentration$total_vol_sampled * 1e6
# # Select desired seascapes and reorder categories in X axis
spp_concentration$X8.day.seascapes <- factor(spp_concentration$X8.day.seascapes, levels = c("3", "5", "7", "11", "13", "15","21","27"))
# Filter out seascape class as desired
# exclude_classes <- c(5, 7, 11)
# spp_concentration <- spp_concentration[!spp_concentration$X8.day.seascapes %in% exclude_classes, ]
custom_pal_hex2 <- c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf')
# Create the stack plot
concentration_stackplot <- ggplot(spp_concentration, aes(x = X8.day.seascapes, y = species_per_cubic_meter, fill = species)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = custom_pal_hex2) +
labs(x = "Seascape class", y = "Species concentration (org. m"^"-3"~")") +
theme_minimal() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 16))
concentration_stackplot

# Calculate percentages
spp_concentration_percent <- spp_concentration %>%
group_by(X8.day.seascapes) %>%
mutate(total_concentration = sum(species_per_cubic_meter),
species_percentage = (species_per_cubic_meter / total_concentration) * 100)
# Create the stacked plot
concentration_percent_stackplot <- ggplot(spp_concentration_percent, aes(x = X8.day.seascapes, y = species_percentage, fill = species)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = custom_pal_hex2) +
labs(x = "Seascape class", y = "Relative concentration (%)") +
theme_minimal() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 16))
concentration_percent_stackplot

# Gather columns containing species counts into key-value pairs and calculate concentrations
spp_concentration_long <- spp_df %>%
gather(key = "species", value = "count", -(X8.day.seascapes:date)) %>%
mutate(concentration = (count / total_vol_sampled) * 1e6)
# Calculate the mean concentration and its standard deviation per species and 8X.day.seascapes category. This is likely more representative since the approach will capture high concentration events (high counts in low volumes) that otherwise get filtered out when using an overall integrated sampled volume and total counts for the total concentration.
avg_concentration_per_class <- spp_concentration_long %>%
group_by(species, `X8.day.seascapes`) %>%
summarize(
mean_concentration = mean(concentration, na.rm = TRUE),
sd_concentration = sd(concentration, na.rm = TRUE)
)
`summarise()` has grouped output by 'species'. You can override using the `.groups` argument.
avg_concentration_per_class$X8.day.seascapes <- factor(avg_concentration_per_class$X8.day.seascapes, levels = c("3", "5", "7", "11", "13", "15","21","27"))
avg_stackplot <- ggplot(avg_concentration_per_class, aes(x = X8.day.seascapes, y = mean_concentration, fill = species)) +
geom_bar(stat = "identity") +
# scale_fill_manual(values = custom_pal_hex2) + # use for zooplankton
scale_colour_brewer(palette = "Set1") + # use for phytoplankton
labs(x = "Seascape class", y = "Mean density (org. m"^"-3"~")") +
theme_minimal() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 16))
avg_stackplot

# Calculate percentages
avg_concentration_percent <- avg_concentration_per_class %>%
group_by(`X8.day.seascapes`) %>%
mutate(mean_concentration_percent = mean_concentration / sum(mean_concentration) * 100)
avg_percent_stackplot <- ggplot(avg_concentration_percent, aes(x = X8.day.seascapes, y = mean_concentration_percent, fill = species)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = custom_pal_hex2) + # use for zooplankton
# scale_colour_brewer(palette = "Set2") + # use for phytoplankton
labs(x = "Seascape class", y = "Relative concentration (%)") +
theme_minimal() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 16))
avg_percent_stackplot

Generate plots
library(tidyverse)
library(hrbrthemes)
NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow
library(viridis)
Loading required package: viridisLite
# # Load seascape color palette used with Matlab and extract RGB values for observed unique seascapes
# For NOAA machines
# palette_dir <- "/Users/enrique.montes/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/software/matlab/m_map/seascape_cm"
# For personal machine
palette_dir <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/software/matlab/m_map/seascape_cm"
palette_file <- list.files(path = palette_dir, pattern = "cmap1.csv", full.names = TRUE)
palette_df <- read.csv(palette_file, header = FALSE)
colnames(palette_df) <- c("r", "g", "b")
unique_seascapes <- sort(unique(na.omit(ctd_meta$X8.day.seascapes)))
subset_palette_df <- palette_df[unique_seascapes, ]
# set RGB values for the plots
r_vals <- round(subset_palette_df$r * 255, 0)
g_vals <- round(subset_palette_df$g * 255, 0)
b_vals <- round(subset_palette_df$b * 255, 0)
custom_pal <- cbind(r_vals, g_vals, b_vals)
custom_pal_hex <- rgb(custom_pal[, 1], custom_pal[, 2], custom_pal[, 3], maxColorValue=255)
# pal_final <- c(custom_pal_hex[3], custom_pal_hex[4], custom_pal_hex[5], )
# filter out rows with NA values in column seascapes
df_filtered <- taxa_meta[complete.cases(taxa_meta$X8.day.seascapes),]
# Convert the 'x' column to character
df_filtered$X8.day.seascapes <- as.character(df_filtered$X8.day.seascapes)
# # Reorder seascape categories in X axis
df_filtered$X8.day.seascapes <- factor(df_filtered$X8.day.seascapes, levels = c("3", "5", "7", "11", "13", "15","21","27"))
# Define custom colors for each level
custom_colors <- c("3" = custom_pal_hex[1], "5" = custom_pal_hex[2], "7" = custom_pal_hex[3],
"11" = custom_pal_hex[4], "13" = custom_pal_hex[5], "15" = custom_pal_hex[6],
"21" = custom_pal_hex[7], "27" = custom_pal_hex[8])
# Filter out seascape class as desired
# df_filtered <- df_filtered[df_filtered$X8.day.seascapes != "5", ]
# Plot
# See https://cran.r-project.org/web/packages/viridis/vignettes/intro-to-viridis.html for color palette options
pp <- df_filtered %>%
ggplot( aes(x=X8.day.seascapes, y=Avg.chl.a..ug.L., fill=X8.day.seascapes)) +
geom_boxplot() +
# scale_fill_viridis(option="H", discrete = TRUE, alpha=0.6) +
scale_fill_manual(values = custom_colors) +
geom_jitter(color="grey", size=0.8, alpha=0.4) +
labs(x = "Seascape class") +
labs(y = expression("["*Chl-a*"]"~ mu*"g"~L^-1)) +
# labs(y = expression("Salinity")) +
# labs(y = expression(paste("Temperature (", degree, "C) at 1 m depth"))) +
# labs(y = expression("["*DO*"]"~mg~L^-1)) +
# labs(y = expression("["*NO["x"]*"]" ~ mu*"M")) +
# labs(y = expression("["*PO[4]^"3-"*"]" ~ mu*"M")) +
# labs(y = expression("["*NH[4]^"+"*"]" ~ mu*"M")) +
# theme(axis.title.y = element_text(hjust = 1))
# scale_x_discrete(labels= c("Tropical/Subtropical Upwelling",
# "Tropical Seas",
# "Warm, Blooms, High Nuts",
# "Tropical/Subtropical Transition",
# "Temperate Transition")) +
theme_ipsum() +
theme(
legend.position="none",
plot.title = element_text(size=11)
) +
# ggtitle("A boxplot with jitter") +
# theme(axis.text.x = element_text(angle = 45)) +
ylim(0, 7) +
theme(axis.text.x = element_text(size = 32, family = "Arial"), # Set X-axis label font size
axis.text.y = element_text(size = 32, family = "Arial")) +
theme(axis.title.x = element_text(size = 18, hjust = 0.5, family = "Arial"),
axis.title.y = element_text(size = 18, hjust = 0.5, family = "Arial")) +
theme(legend.text = element_text(size = 32))
pp
Warning: Removed 184 rows containing non-finite values (`stat_boxplot()`).
Warning: Removed 184 rows containing missing values (`geom_point()`).

Create stackplots showing relative frequency using counts only of
plankton taxa per seascape category
# convert abundance columns to relative frequency
# subsets taxa for zooplankton
# df_subset <- df_filtered[ , c("X8.day.seascapes",
# "Acantharea",
# "Copepods",
# "Echinoderms",
# "Jellies",
# "Larvaceans",
# "Polychaetes",
# "Chaetognaths",
# "Pteropods")]
# subsets taxa for phytoplankton
df_subset <- df_filtered[ , c("X8.day.seascapes",
"Ceratium",
"Chaetoceros",
"Chain2",
"Chain3",
"Guinardia",
"Neocalyptrella",
"Tricho")]
# subsets taxa for all species
# df_subset <- df_filtered[ , c("X8.day.seascapes",
# "Ceratium",
# "Chaetoceros",
# "Diatoms",
# "Diatoms2",
# "Guinardia",
# "Neocalyptrella",
# "Trichodesmium",
# "Acantharea",
# "Copepods",
# "Echinoderms",
# "Jellies",
# "Larvaceans",
# "Polychaetes",
# "Chaetognaths",
# "Pteropods")]
# reshape the data to long format
df_long <- tidyr::gather(df_subset, key = "Species", value = "Frequency", -X8.day.seascapes)
# calculate relative frequencies
df_sum <- df_long %>%
group_by(X8.day.seascapes, Species) %>%
summarise(n = sum(Frequency)) %>%
mutate(freq = n / sum(n))
`summarise()` has grouped output by 'X8.day.seascapes'. You can override using the `.groups` argument.
# Seascape class names:
# "Class 11" - Tropical/Subtropical Upwelling
# "Class 15" - Tropical Seas
# "Class 21" - Warm, Blooms, High Nuts
# "Class 3" - Tropical/Subtropical Transition
# "Class 7" - Temperate Transition
# # Select desired seascapes and reorder categories in X axis
df_sum$X8.day.seascapes <- factor(df_sum$X8.day.seascapes, levels = c("3", "5", "7", "11", "13", "15","21","27"))
# Filter out seascape class as desired
exclude_classes <- c(5, 7, 11)
df_sum <- df_sum[!df_sum$X8.day.seascapes %in% exclude_classes, ]
# Use qualitative palettes: https://colorbrewer2.org/#type=qualitative&scheme=Accent&n=7
custom_pal_hex2 <- c('#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf')
# custom_pal_hex2 <- c('#1b9e77','#d95f02','#7570b3','#e7298a','#66a61e','#e6ab02','#a6761d')
# create the stackplot
qq <- ggplot(df_sum, aes(x = X8.day.seascapes, y = freq, fill = Species)) +
# scale_fill_viridis(option="Set3", discrete = TRUE, alpha=0.8) +
scale_fill_viridis(discrete = TRUE, alpha=0.8) +
# scale_fill_manual(values = custom_pal_hex2) +
geom_bar(stat = "identity") +
labs(x = "Seascape class") +
labs(y = "Relative frequency") +
# scale_x_discrete(labels= c("Tropical/Subtropical Upwelling",
# "Tropical Seas",
# "Warm, Blooms, High Nuts",
# "Tropical/Subtropical Transition",
# "Temperate Transition")) +
# theme(axis.text.x = element_text(angle = 45)) +
theme_minimal() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 16))
#theme(axis.text.x = element_text(hjust = 1))
qq

Compute Shannon Index
library(dplyr)
library(vegan)
# Select species for Shannon calculation
df_subset_shannon <- df_filtered[ , c("X8.day.seascapes",
"Acantharea",
"Copepods",
"Echinoderms",
"Jellies",
"Larvaceans",
"Polychaets",
"Chaetognaths",
"Pteropods",
"Ceratium",
"Chaetoceros",
"Chain2",
"Chain3",
"Guinardia",
"Neocalyptrella",
"Tricho")]
# reshape the data to long format
df_long <- tidyr::gather(df_subset_shannon, key = "Species", value = "Abundance", -X8.day.seascapes)
# Exclude seascapes
exclude_seascapes <- c(5, 7, 11)
# Compute Shannon diversity per seascape class
shannon_df <- df_long %>%
group_by(X8.day.seascapes) %>%
summarise(shannon = diversity(Abundance, index = "shannon"))
# Filter the data to exclude specified seascapes
shannon_df_filtered <- shannon_df[!shannon_df$X8.day.seascapes %in% exclude_seascapes, ]
# create the bar plot of Shannon diversity
ff <- ggplot(shannon_df_filtered, aes(x = X8.day.seascapes, y = shannon, fill = X8.day.seascapes)) +
geom_bar(stat = "identity") +
# scale_fill_viridis(option="plasma", discrete = TRUE, alpha=0.6) +
scale_fill_manual(values = custom_colors) +
xlab("Seascape Class") +
ylab("Shannon Diversity") +
# scale_x_discrete(labels= c("Tropical/Subtropical Upwelling",
# "Tropical Seas",
# "Warm, Blooms, High Nuts",
# "Tropical/Subtropical Transition",
# "Temperate Transition")) +
# theme(axis.text.x = element_text(angle = 45)) +
theme(axis.text.x = element_text(size = 32), # Set X-axis label font size
axis.text.y = element_text(size = 32)) +
theme(axis.title.x = element_text(size = 32),
axis.title.y = element_text(size = 32)) +
theme(legend.text = element_text(size = 32)) +
guides()
ff
# # Subset the data to exclude specified seascapes
filtered_taxa_meta <- taxa_meta[complete.cases(taxa_meta$X8.day.seascapes), ]
filtered_taxa_meta <- filtered_taxa_meta[!filtered_taxa_meta$X8.day.seascapes %in% exclude_seascapes, ]
# # Plot sampled seascape frequency
tt <- ggplot(filtered_taxa_meta, aes(x = factor(X8.day.seascapes), fill = factor(X8.day.seascapes))) +
geom_bar(color = "black", alpha = 0.7) +
scale_fill_manual(values = custom_colors) +
labs(x = "Seascape Class", y = "Frequency") +
theme_minimal() +
theme(axis.text.x = element_text(size = 22), # Set X-axis label font size
axis.text.y = element_text(size = 22)) +
theme(axis.title.x = element_text(size = 22),
axis.title.y = element_text(size = 22)) +
theme(legend.text = element_text(size = 22)) +
guides(fill = FALSE)
tt
# # Counts of species per seascape
df_sum_abund <- df_long %>%
group_by(X8.day.seascapes, Species) %>%
summarise(n = sum(Abundance))
df_sum_abund_filt <- df_sum_abund[df_sum_abund$Species == "Pteropods",]
# Filter the data to exclude specified seascapes
df_sum_abund_filt2 <- df_sum_abund_filt[!df_sum_abund_filt$X8.day.seascapes %in% exclude_seascapes, ]
dd <- ggplot(df_sum_abund_filt2, aes(x = factor(X8.day.seascapes), y = n, fill = factor(X8.day.seascapes))) +
geom_bar(color = "black", alpha = 0.7, stat = "identity") +
# scale_fill_viridis(option = "magma", discrete = TRUE, alpha = 0.8)
scale_fill_manual(values = custom_colors) +
theme_minimal()
dd
# Compute counts of selected species per seascape class normalized by frequency of seascapes
# reshape the data to long format
df_long2 <- tidyr::gather(df_subset_shannon, key = "Species", value = "Abundance", -X8.day.seascapes)
spp_seascape_normalized <- df_long2 %>%
filter(Species == "Pteropods") %>%
group_by(X8.day.seascapes) %>%
summarise(spp_count = sum(Abundance))
# Compute frequencies of each seascape class
seascape_frequencies <- df_long2 %>%
count(X8.day.seascapes) %>%
rename(freq = n)
# Merge counts with frequencies
spp_seascape_normalized <- merge(spp_seascape_normalized, seascape_frequencies, by = "X8.day.seascapes")
# Normalize counts by frequency
spp_seascape_normalized$spp_normalized <- (spp_seascape_normalized$spp_count / spp_seascape_normalized$freq) * 1000
spp_seascape_normalized_filt <- spp_seascape_normalized[!spp_seascape_normalized$X8.day.seascapes %in% exclude_seascapes, ]
bb <- ggplot(spp_seascape_normalized_filt, aes(x = factor(X8.day.seascapes), y = spp_normalized, fill = factor(X8.day.seascapes))) +
geom_bar(color = "black", alpha = 0.7, stat = "identity") +
scale_fill_manual(values = custom_colors) +
labs(x = "Seascape Class", y = "Counts / Seascape freq * 1000") +
theme_minimal() +
# theme(axis.text.x = element_text(size = 32), # Set X-axis label font size
# axis.text.y = element_text(size = 32)) +
# theme(axis.title.x = element_text(size = 32),
# axis.title.y = element_text(size = 32)) +
# theme(legend.text = element_text(size = 32)) +
guides()
bb
PC plot
library(ggalt)
Registered S3 methods overwritten by 'ggalt':
method from
grid.draw.absoluteGrob ggplot2
grobHeight.absoluteGrob ggplot2
grobWidth.absoluteGrob ggplot2
grobX.absoluteGrob ggplot2
grobY.absoluteGrob ggplot2
# Perform principal component analysis on the count data
# for hydrography
sel_vars <- c(
"X8.day.seascapes",
"salinity",
"Avg.chl.a..ug.L.",
"PO4...uM.",
"NO3.NO2..uM.",
"NH4...uM.",
"temp..degC.")
# for taxonomy
# sel_vars <- c("X8.day.seascapes",
# "Acantharea",
# "Copepods",
# "Echinoderms",
# "Jellies",
# "Larvaceans",
# "Polychaets",
# "Chaetognaths",
# "Pteropods")
# sel_vars <- c("X8.day.seascapes",
# "Ceratium",
# "Chaetoceros",
# "Chain2",
# "Chain3",
# "Guinardia",
# "Neocalyptrella",
# "Tricho")
# sel_vars <- c("X8.day.seascapes",
# "Acantharea",
# "Copepods",
# "Echinoderms",
# "Jellies",
# "Larvaceans",
# "Polychaets",
# "Chaetognaths",
# "Pteropods",
# "Ceratium",
# "Chaetoceros",
# "Chain2",
# "Chain3",
# "Guinardia",
# "Neocalyptrella",
# "Tricho")
# filter out rows with NA values in column seascapes
# df_filtered_pca <- taxa_meta[complete.cases(taxa_meta$X8.day.seascapes), ]
df_filtered_pca <- taxa_meta[complete.cases(taxa_meta[, sel_vars]), ]
# exclude_seascapes <- c(5, 7, 11)
exclude_seascapes <- 0
filt_df_pca <- df_filtered_pca[!df_filtered_pca$X8.day.seascapes %in%
exclude_seascapes, sel_vars]
# Select numeric columns in filt_df_pca
numeric_cols <- sapply(filt_df_pca, is.numeric)
# Identify numeric columns except the first one
numeric_cols <- 2:ncol(filt_df_pca)
# Transform numeric columns to log scale
filt_df_pca[numeric_cols] <- lapply(filt_df_pca[numeric_cols], function(x) log(x + 1))
# pca <- prcomp(filt_df_pca[, c("salinity", "Avg.chl.a..ug.L.", "PO4...uM.", "NO3.NO2..uM.")], scale. = TRUE)
pca <- prcomp(filt_df_pca[, -1], scale. = TRUE)
# Extract PC1 and PC2 scores for each sampling event
# pc_scores <- data.frame(seascape = df_subset$X8.day.seascapes, # for taxonomic analysis
pc_scores <- data.frame(seascape = as.character(filt_df_pca$X8.day.seascapes), # for hydrography
PC1 = pca$x[, 1],
PC2 = pca$x[, 2])
# Create the plot
pc_scores$seascape <- factor(pc_scores$seascape, levels = c("3", "5", "7", "11", "13", "15", "21", "27"))
bb <- ggplot(pc_scores, aes(x = PC1, y = PC2, color = seascape)) +
geom_point() +
labs(x = "PC1", y = "PC2", color = "Seascape")
# add circle around cluster of data points
# custom_colors_pca <- custom_pal_hex[c(1, 5, 6, 7, 8)]
custom_colors_pca <- custom_colors
yy <- ggplot(pc_scores, aes(x = PC1, y = PC2, color = seascape)) +
geom_point() +
stat_ellipse(aes(fill = seascape), level = 0.90, geom = "polygon", alpha = 0.3, color = "black") +
scale_color_manual(values = custom_colors_pca) +
scale_fill_manual(values = custom_colors_pca) +
theme_classic() +
xlim(-2,2) +
ylim(-2,2) +
# xlim(-1,1) +
# ylim(-1,1) +
geom_point(size=2) +
guides(colour = guide_legend(override.aes = list(size=2))) +
theme(axis.text.x = element_text(size = 32), # Set X-axis label font size
axis.text.y = element_text(size = 32)) +
theme(axis.title.x = element_text(size = 32),
axis.title.y = element_text(size = 32)) +
theme(legend.text = element_text(size = 32))
yy
Warning: Removed 102 rows containing non-finite values (`stat_ellipse()`).
Too few points to calculate an ellipse
Too few points to calculate an ellipse
Warning: Removed 102 rows containing missing values (`geom_point()`).
Warning: Removed 102 rows containing missing values (`geom_point()`).

################################################################################################
# # Create PCA with eigenvectors
# Extract principal component scores
pc_scores2 <- pca$x
# Extract eigenvectors
eigenvectors <- pca$rotation
# Calculate the percentage variance explained by each principal component
total_variance <- sum(pca$sdev^2)
pc_var_percent <- round(100 * (pca$sdev^2) / total_variance, 1)
# Convert X8.day.seascapes to a factor
filt_df_pca$X8.day.seascapes <- as.factor(filt_df_pca$X8.day.seascapes)
# # For hydrography
qq <- ggplot(filt_df_pca, aes(x = pc_scores2[,1], y = pc_scores2[,2], color = X8.day.seascapes)) +
geom_point(size = 3, alpha = 0.7) +
scale_color_manual(values = custom_colors_pca) +
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 1], yend = eigenvectors[2, 1]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC1
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 2], yend = eigenvectors[2, 2]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC2
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 3], yend = eigenvectors[2, 3]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC3
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 4], yend = eigenvectors[2, 4]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC4
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 5], yend = eigenvectors[2, 5]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC5
geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 6], yend = eigenvectors[2, 6]),
arrow = arrow(length = unit(0.1, "inches")), color = "black") + # Add vector for PC6
geom_text(aes(x = eigenvectors[1, 1], y = eigenvectors[2, 1],
label = paste("PC1 (", pc_var_percent[1], "%: Salinity)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC1
geom_text(aes(x = eigenvectors[1, 2], y = eigenvectors[2, 2],
label = paste("PC2 (", pc_var_percent[2], "%: Chla)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC2
geom_text(aes(x = eigenvectors[1, 3], y = eigenvectors[2, 3],
label = paste("PC3 (", pc_var_percent[3], "%: Phosphate)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC3
geom_text(aes(x = eigenvectors[1, 4], y = eigenvectors[2, 4],
label = paste("PC4 (", pc_var_percent[4], "%: NOx)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC4
geom_text(aes(x = eigenvectors[1, 5], y = eigenvectors[2, 5],
label = paste("PC5 (", pc_var_percent[5], "%: Ammonium)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC5
geom_text(aes(x = eigenvectors[1, 6], y = eigenvectors[2, 6],
label = paste("PC6 (", pc_var_percent[6], "%: Temperature)", sep = "")),
vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC6
labs(x = "PC1", y = "PC2", color = "Seascape class") +
xlim(-1.5, 1.5) +
ylim(-1.5, 1.5) +
guides(colour = guide_legend(override.aes = list(size=5))) +
theme_classic() +
theme(axis.text.x = element_text(size = 18), # Set X-axis label font size
axis.text.y = element_text(size = 18)) +
theme(axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18)) +
theme(legend.text = element_text(size = 18)) +
theme(legend.title = element_text(size = 18))
qq
Warning: Removed 196 rows containing missing values (`geom_point()`).

# # # For phytoplankton
# qq2 <- ggplot(filt_df_pca, aes(x = pc_scores2[,1], y = pc_scores2[,3], color = X8.day.seascapes)) +
# geom_point(size = 4) +
# scale_color_manual(values = custom_colors_pca) +
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 1], yend = eigenvectors[2, 1]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC1
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 2], yend = eigenvectors[2, 2]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC2
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 3], yend = eigenvectors[2, 3]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC3
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 4], yend = eigenvectors[2, 4]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC4
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 5], yend = eigenvectors[2, 5]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC5
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 6], yend = eigenvectors[2, 6]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC6
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 7], yend = eigenvectors[2, 7]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC7
# geom_text(aes(x = eigenvectors[1, 1], y = eigenvectors[2, 1],
# label = paste("PC1 (", pc_var_percent[1], "%: Ceratium)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC1
# geom_text(aes(x = eigenvectors[1, 2], y = eigenvectors[2, 2],
# label = paste("PC2 (", pc_var_percent[2], "%: Chaetoceros)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC2
# geom_text(aes(x = eigenvectors[1, 3], y = eigenvectors[2, 3],
# label = paste("PC3 (", pc_var_percent[3], "%: Diatoms)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC3
# geom_text(aes(x = eigenvectors[1, 4], y = eigenvectors[2, 4],
# label = paste("PC4 (", pc_var_percent[4], "%: Diatoms2)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC4
# geom_text(aes(x = eigenvectors[1, 5], y = eigenvectors[2, 5],
# label = paste("PC5 (", pc_var_percent[5], "%: Guinardia)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC5
# geom_text(aes(x = eigenvectors[1, 6], y = eigenvectors[2, 6],
# label = paste("PC6 (", pc_var_percent[6], "%: Neocalyptrella)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC6
# geom_text(aes(x = eigenvectors[1, 7], y = eigenvectors[2, 7],
# label = paste("PC7 (", pc_var_percent[7], "%: Trichodesmium)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC7
# labs(x = "PC1", y = "PC3", color = "X8.day.seascapes") +
# xlim(-1, 1) +
# ylim(-1, 1) +
# guides(colour = guide_legend(override.aes = list(size=2))) +
# theme_classic() +
# theme(axis.text.x = element_text(size = 32), # Set X-axis label font size
# axis.text.y = element_text(size = 32)) +
# theme(axis.title.x = element_text(size = 32),
# axis.title.y = element_text(size = 32)) +
# theme(legend.text = element_text(size = 32))
# qq2
#
#
# # # For zooplankton
# qq3 <- ggplot(filt_df_pca, aes(x = pc_scores2[,1], y = pc_scores2[,2], color = X8.day.seascapes)) +
# geom_point(size = 4) +
# scale_color_manual(values = custom_colors_pca) +
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 1], yend = eigenvectors[2, 1]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC1
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 2], yend = eigenvectors[2, 2]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC2
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 3], yend = eigenvectors[2, 3]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC3
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 4], yend = eigenvectors[2, 4]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC4
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 5], yend = eigenvectors[2, 5]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC5
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 6], yend = eigenvectors[2, 6]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC6
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 7], yend = eigenvectors[2, 7]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC7
# geom_segment(aes(x = 0, y = 0, xend = eigenvectors[1, 8], yend = eigenvectors[2, 8]),
# arrow = arrow(length = unit(0.2, "inches")), color = "black") + # Add vector for PC8
# geom_text(aes(x = eigenvectors[1, 1], y = eigenvectors[2, 1],
# label = paste("PC1 (", pc_var_percent[1], "%: Acantharea)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC1
# geom_text(aes(x = eigenvectors[1, 2], y = eigenvectors[2, 2],
# label = paste("PC2 (", pc_var_percent[2], "%: Copepods)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC2
# geom_text(aes(x = eigenvectors[1, 3], y = eigenvectors[2, 3],
# label = paste("PC3 (", pc_var_percent[3], "%: Echinoderms)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC3
# geom_text(aes(x = eigenvectors[1, 4], y = eigenvectors[2, 4],
# label = paste("PC4 (", pc_var_percent[4], "%: Jellies)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC4
# geom_text(aes(x = eigenvectors[1, 5], y = eigenvectors[2, 5],
# label = paste("PC5 (", pc_var_percent[5], "%: Larvaceans)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC5
# geom_text(aes(x = eigenvectors[1, 6], y = eigenvectors[2, 6],
# label = paste("PC6 (", pc_var_percent[6], "%: Polychaetes)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC6
# geom_text(aes(x = eigenvectors[1, 7], y = eigenvectors[2, 7],
# label = paste("PC7 (", pc_var_percent[7], "%: Chaetognaths)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC7
# geom_text(aes(x = eigenvectors[1, 8], y = eigenvectors[2, 8],
# label = paste("PC8 (", pc_var_percent[8], "%: Pteropods)", sep = "")),
# vjust = -0.5, hjust = 0.5, color = "black") + # Add label for PC8
# labs(x = "PC1", y = "PC2", color = "X8.day.seascapes") +
# xlim(-1, 1) +
# ylim(-1, 1) +
# guides(colour = guide_legend(override.aes = list(size=2))) +
# theme_classic() +
# theme(axis.text.x = element_text(size = 32), # Set X-axis label font size
# axis.text.y = element_text(size = 32)) +
# theme(axis.title.x = element_text(size = 32),
# axis.title.y = element_text(size = 32)) +
# theme(legend.text = element_text(size = 32))
# qq3
Map overall WEIGHTED mean concentration values of selected taxa by
transect
# install.packages("svglite")
library(ggOceanMaps)
Warning: package ‘ggOceanMaps’ was built under R version 4.2.3
ggOceanMaps: Setting data download folder to a temporary folder
/var/folders/pj/01bgh26153x4c6rjpm45t1hrt405dy/T//Rtmp1csphH. This means that any downloaded map
data need to be downloaded again when you restart R. To avoid this problem, change the default
path to a permanent folder on your computer. Add following lines to your .Rprofile file:
{.ggOceanMapsenv <- new.env(); .ggOceanMapsenv$datapath <- 'YourCustomPath'}. You can use
usethis::edit_r_profile() to edit the file. '~/ggOceanMapsLargeData' would make it in a writable
folder on most operating systems.
library(leaflet)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
# library(patchwork)
# List of class names
# Acantharea, Chaetognaths, Ostracods, Copepods, Decapods, Echinoderms, Jellies, Larvaceans, Polychaets, Pteropods
# Centric, Ceratium, Chaetoceros, Chain2, Chain3, Guinardia, Neocalyptrella, Noctiluca, Tricho
selected_class <- "Tricho"
# For zooplankton
taxa_meta_concentration <- taxa_meta %>%
mutate(across(all_of(selected_class), ~ . / total_vol_sampled * 1e6)) %>%
select(Station, dec_lat, dec_lon, year, month, date, total_vol_sampled, all_of(selected_class)) %>%
filter(!is.na(total_vol_sampled))
# # For phytoplankton
# taxa_meta_concentration <- taxa_meta %>%
# mutate(across(c(Centric,Ceratium,Chaetoceros,Chain2,Chain3,Guinardia,Neocalyptrella,
# Noctiluca,Tricho), ~ ./total_vol_sampled * 1e6)) %>%
# select(Station, dec_lat, dec_lon, year, month, date, Avg.chl.a..ug.L.,
# temp..degC., salinity,total_vol_sampled,
# Centric,Ceratium,Chaetoceros,Chain2,Chain3,Guinardia,Neocalyptrella,
# Noctiluca,Tricho) %>%
# filter(!is.na(total_vol_sampled))
# Get station coordinates
path_sfer_list <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/proposals/2022_02_MultiStressor_NOAA/module_1"
sfer_curated <- list.files(path_sfer_list, pattern = "sfer_stations_curated.csv", full.names = TRUE)
sfer_sta_list <- read.csv(sfer_curated, header = TRUE)
# # Merges curated station list with the concentration df
concentration_df <- taxa_meta_concentration %>%
left_join(sfer_sta_list %>% filter(station_class %in% "C"), by = c('Station' = 'station_id')) %>%
filter(get(selected_class) > 0) # Exclude rows where the species count is zero
# Compute weighted average lat/lons and mean variable values for the current class
taxa_concentration_avg <- concentration_df %>%
group_by(line_id) %>%
mutate(weight = get(selected_class) / sum(get(selected_class), na.rm = TRUE)) %>%
summarise(longitude = weighted.mean(dec_lon, w = weight, na.rm = TRUE),
latitude = weighted.mean(dec_lat, w = weight, na.rm = TRUE),
sel_taxa_mean = mean(get(selected_class), na.rm = TRUE),
sel_taxa_sd = sd(get(selected_class), na.rm = TRUE))
# Prepare data for mapping
dt <- data.frame(
lon = taxa_concentration_avg$longitude,
lat = taxa_concentration_avg$latitude,
mean_param = taxa_concentration_avg$sel_taxa_mean,
sd_param = taxa_concentration_avg$sel_taxa_sd) %>%
mutate(sd_param = replace_na(sd_param, 0))
# Add station markers
station_markers <- sfer_sta_list %>% filter(station_class %in% "C")
# Create the map
concentration_map <- basemap(limits = c(-86, -79.5, 24, 28.5), bathymetry = TRUE) +
# geom_point(data = dt, aes(x = lon, y = lat, size = log10(mean_param+1), color = log10(sd_param+1))) +
geom_point(data = dt, aes(x = lon, y = lat, size = mean_param, color = sd_param)) +
scale_color_gradient(low = "yellow", high = "red", na.value = NA, name = "Standard Deviation") +
geom_point(data = station_markers, aes(x = mean_lon, y = mean_lat), color = "black", shape = 3, size = 1.5) +
scale_size_continuous(name = "Average concentration",
# breaks = c(2000, 4000, 6000),
range = c(0, 10),
guide = guide_legend(override.aes = list(color = "black", fill = "white"))) +
theme_minimal() +
ggtitle(paste(selected_class))
# Optionally, save each map as an image
ggsave(paste0("conc_map_weighted_", selected_class, ".png"), plot = concentration_map, width = 8, height = 6)
ggsave(paste0("conc_map_weighted_", selected_class, ".svg"), plot = concentration_map, width = 8, height = 6, device = "svg")
print(concentration_map)

Map overall mean concentration values of selected taxa per
station
# List of class names
# Acantharea, Chaetognaths, Ostracods, Copepods, Decapods, Echinoderms, Jellies, Larvaceans, Polychaets, Pteropods, pellets
# Centric, Ceratium, Chaetoceros, Chain2, Chain3, Guinardia, Neocalyptrella, Noctiluca, Tricho
selected_class <- "pellets"
taxa_meta_concentration <- taxa_meta %>%
mutate(across(all_of(selected_class), ~ . / total_vol_sampled * 1e6)) %>%
select(Station, dec_lat, dec_lon, year, month, date, total_vol_sampled, all_of(selected_class)) %>%
filter(!is.na(total_vol_sampled))
# Compute mean concentration of selected groups per station
taxa_concentration_avg_station <- taxa_meta_concentration %>%
group_by(Station) %>%
summarise(longitude_station = mean(dec_lon, na.rm = TRUE),
latitude_station = mean(dec_lat, na.rm = TRUE),
sel_taxa_mean_station = mean(get(selected_class), na.rm = TRUE),
sel_taxa_sd_station = sd(get(selected_class), na.rm = TRUE))
# Get station coordinates
path_sfer_list <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/proposals/2022_02_MultiStressor_NOAA/module_1"
sfer_curated <- list.files(path_sfer_list, pattern = "sfer_stations_curated.csv", full.names = TRUE)
sfer_sta_list <- read.csv(sfer_curated, header = TRUE)
# # Map with bathymetry
# Overlay color-scaled dots
dt_station <- data.frame(
lon_station = taxa_concentration_avg_station$longitude_station,
lat_station = taxa_concentration_avg_station$latitude_station,
mean_param_station = taxa_concentration_avg_station$sel_taxa_mean_station,
sd_param_station = taxa_concentration_avg_station$sel_taxa_sd_station)
# Replace NA by zeros
dt_station <- dt_station %>%
mutate(sd_param_station = replace_na(sd_param_station, 0))
# Add station markers
station_markers <- sfer_sta_list %>% filter(station_class %in% "C")
concentration_map_station <- basemap(limits = c(-86, -79.5, 24, 28.5), bathymetry = TRUE) +
geom_point(data = dt_station, aes(x = lon_station,
y = lat_station,
size = mean_param_station,
color = sd_param_station)) +
scale_color_gradient(low = "yellow", high = "red", na.value = NA, name = "Standard Deviation") +
geom_point(data = station_markers, aes(x = mean_lon, y = mean_lat), color = "black", shape = 3, size = 1.5) +
scale_size_continuous(name = "Average concentration",
# breaks = c(250, 500, 750),
range = c(1, 10),
guide = guide_legend(override.aes = list(color = "black", fill = "white"))) +
theme_minimal()
# Optionally, save each map as an image
# ggsave(paste0("conc_map_station_", selected_class, ".png"), plot = concentration_map_station, width = 8, height = 6)
ggsave(paste0("conc_map_station_", selected_class, ".svg"), plot = concentration_map_station, width = 8, height = 6, device = "svg")
print(concentration_map_station)

write.csv(dt_station, paste0("df_",selected_class,".csv"), row.names = FALSE)
print(max(dt_station$mean_param_station))
[1] 12187.69
Map mean count values of selected taxa and specified dates
# # ggOceanMaps:
# https://biostats-r.github.io/biostats/workingInR/140_maps.html
# https://github.com/MikkoVihtakari/ggOceanMaps: Use this one: remotes::install_github("MikkoVihtakari/ggOceanMaps")
# install.packages("ggOceanMaps") # # This is outdated, don't use!!!
library(ggOceanMaps)
library(leaflet)
# For NOAA machines
# path_sfer_list <- "/Users/enrique.montes/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/proposals/2022_02_MultiStressor_NOAA/module_1"
# For personal machine
path_sfer_list <- "~/Library/CloudStorage/GoogleDrive-enriquemontes01@gmail.com/My Drive/GDrive/proposals/2022_02_MultiStressor_NOAA/module_1"
sfer_curated <- list.files(path_sfer_list, pattern = "sfer_stations_curated.csv", full.names = TRUE)
sfer_sta_list <- read.csv(sfer_curated, header = TRUE)
merged_data <- taxa_meta %>%
left_join(sfer_sta_list %>% filter(station_class %in% "C"), by = c('Station' = 'station_id'))
# Replace 2023 and 10 with your selected year and month
selected_year <- 2023
selected_month <- 11
# Filter rows
filtered_taxa_meta <- merged_data %>%
filter(year == selected_year, month == selected_month)
# filtered_taxa_meta <- merged_data
# Compute weighted average lat lons based on selected variable, and mean variable values (e.g., Copepods)
taxa_avg <- filtered_taxa_meta %>%
group_by(line_id) %>%
mutate(weight = Guinardia / sum(Guinardia, na.rm = TRUE)) %>%
summarise(longitude = weighted.mean(dec_lon, w = weight, na.rm = TRUE),
latitude = weighted.mean(dec_lat, w = weight, na.rm = TRUE),
sel_taxa_mean = mean(Guinardia, na.rm = TRUE))
# # Filter out values less than 1
filtered_taxa_avg <- taxa_avg %>%
filter(sel_taxa_mean > 0)
# Find the minimum and maximum values of sel_taxa_mean
min_value <- min(filtered_taxa_avg$sel_taxa_mean, na.rm = TRUE)
max_value <- max(filtered_taxa_avg$sel_taxa_mean, na.rm = TRUE)
# # Adjust the color palette with specified values
# color_palette <- colorNumeric(palette = "Oranges", domain = c(min_value, max_value))
# # Create the map
# map <- leaflet(filtered_taxa_avg) %>%
# addProviderTiles("Esri.WorldImagery") %>%
# addCircleMarkers(
# lng = ~longitude,
# lat = ~latitude,
# radius = 10,
# color = ~color_palette(sel_taxa_mean),
# fillOpacity = 0.8,
# popup = ~paste("Line ID: ", line_id, "<br>Copepods: ", sel_taxa_mean)
# ) %>%
# addLegend(
# position = "bottomright",
# pal = color_palette,
# values = c(min_value, max_value), # Adjusted values here
# title = "Copepod occurrences",
# opacity = 1
# )
# map
# # Map with bathymetry
# Overlay color-scaled dots
dt <- data.frame(
lon = filtered_taxa_avg$longitude,
lat = filtered_taxa_avg$latitude,
sel_param = filtered_taxa_avg$sel_taxa_mean)
# # Colors:
# Acantharea = darkturquoise; breaks = c(0.25, 1, 2.5, 5); limits = c(0.1, 10)
# Copepods = red; breaks = c(0.25, 1, 2.5, 5, 10); limits = c(0.1, 15)
# Chain diatoms = orange; breaks = c(0.5, 1, 10, 30, 60); c(0.1, 70)
# Chaetoceros = purple; breaks = c(0.25, 1, 2.5, 5, 10); limits = c(0.1, 15)
# Echinoderms = magenta; breaks = c(0.5, 1, 3, 5); limits = c(0.1, 5)
# Larvaceans = plum; breaks = c(0.5, 1, 3, 5); limits = c(0.1, 5)
# Polychaetes = dodgerblue; breaks = c(0.25, 0.5, 1, 3); limits = c(0.1, 3)
# Jellies = slategray4; breaks = c(0.25, 0.5, 1, 2); limits = c(0.1, 3)
occ_map <- basemap(limits = c(-84, -79.5, 24, 28.5), bathymetry = TRUE) +
geom_point(data = dt, aes(x = lon, y = lat, size = sel_param), fill = "olivedrab2", color = "olivedrab2") +
geom_point(data = filtered_taxa_meta, aes(x = dec_lon, y = dec_lat), color = "black", shape = 3, size = 1.5) +
scale_size_continuous(name = "Average counts",
breaks = c(0.5, 1, 3, 5, 10),
limits = c(0.1, 40),
range = c(1, 15)) +
theme_minimal()
occ_map
# occ_map_leg <- ggplot(dt, aes(lon, lat)) +
# geom_point(aes(size = sel_param), fill = "green", color ="green") +
# theme_minimal()
# occ_map_leg
Create time-series plots of selected taxa at specific stations
selected_variable <- 'Chaetoceros'
# # Lower Keys
# selected_line_id <- c('LK','WS','MO','KW')
# # Middle Keys
# selected_line_id <- c('CO', 'CR')
# # Other regions
selected_line_id <- c('CAL')
# Filter the data for the selected line_id
filtered_merged_data <- merged_data[merged_data$line_id %in% selected_line_id, ]
# Remove rows with NAs in relevant columns
monthly_means <- na.omit(filtered_merged_data[, c("date", selected_variable, "line_id")]) %>%
group_by(year_month = format(date, "%Y-%m")) %>%
summarise(mean_value = mean(!!sym(selected_variable), na.rm = TRUE),
se_value = sd(!!sym(selected_variable), na.rm = TRUE) / sqrt(n()))
# Create a time series plot
ggplot(monthly_means, aes(x = year_month, y = mean_value)) +
geom_bar(stat = "identity", fill = "orange") +
geom_errorbar(aes(ymin = mean_value - se_value, ymax = mean_value + se_value),
width = 0.2, # Adjust width as needed
position = position_dodge(width = 0.8)) + # Adjust width as needed
labs(x = "Year-Month", y = "Mean Value") +
ggtitle("Monthly Means of Selected Variable") +
theme_minimal()
Match file name with string ID - DO NOT USE
# library(tidyverse)
# library(lubridate)
# library(dplyr)
#
# # extract relevant part of the strings
# df <- rbind(class.Copepods,
# class.Eucampia,
# class.Noctiluca,
# class.Polychaets,
# class.Acantharea,
# class.Centric,
# class.Ceratium,
# class.Chaetoceros,
# class.Chain2,
# class.Chain3,
# class.Chain4,
# class.Ostracods,
# class.Jellies,
# class.Larvaceans,
# class.pellets)
# sub_strings <- substr(df$V1, start = 10, stop = 22)
# unique_all <- unique(sub_strings)
#
# # select unique dates (this allows to search CTD records per date and time)
# # To find unique dates and times to extract CDT data use: unique_all[grepl("20221209", unique_all)]
#
# id_list <- unique_all
# id_list2 <- as.POSIXct(id_list, format="%Y%m%d_%H%M", tz="UTC")
#
# conc_occ_count <- data.frame(date = as.Date(character()), stringsAsFactors = FALSE)
#
# for ( i in seq_along(id_list)){
# acantha <- as.data.frame(str_count(class.Acantharea$V1, id_list[i]))
# centric <- as.data.frame(str_count(class.Centric$V1, id_list[i]))
# ceratium <- as.data.frame(str_count(class.Ceratium$V1, id_list[i]))
# chaetoceros <- as.data.frame(str_count(class.Chaetoceros$V1, id_list[i]))
# chaetog <- as.data.frame(str_count(class.Chaetognaths$V1, id_list[i]))
# chain2 <- as.data.frame(str_count(class.Chain2$V1, id_list[i]))
# chain3 <- as.data.frame(str_count(class.Chain3$V1, id_list[i]))
# chain4 <- as.data.frame(str_count(class.Chain4$V1, id_list[i]))
# ostra <- as.data.frame(str_count(class.Ostracods$V1, id_list[i]))
# copepods <- as.data.frame(str_count(class.Copepods$V1, id_list[i]))
# decapod <- as.data.frame(str_count(class.Decapods$V1, id_list[i]))
# echino <- as.data.frame(str_count(class.Echinoderms$V1, id_list[i]))
# eucampia <- as.data.frame(str_count(class.Eucampia$V1, id_list[i]))
# jellies <- as.data.frame(str_count(class.Jellies$V1, id_list[i]))
# larvae <- as.data.frame(str_count(class.Larvaceans$V1, id_list[i]))
# nocti <- as.data.frame(str_count(class.Noctiluca$V1, id_list[i]))
# polychaetes <- as.data.frame(str_count(class.Polychaets$V1, id_list[i]))
# tricho <- as.data.frame(str_count(class.Tricho$V1, id_list[i]))
#
# Acantharea <- colSums(acantha != 0)
# Centric <- colSums(centric != 0)
# Ceratium_spp <- colSums(ceratium != 0)
# Chaetoceros <- colSums(chaetoceros != 0)
# Chaetognaths <- colSums(chaetog != 0)
# Diatom_chains_1 <- colSums(chain2 != 0)
# Diatom_chains_2 <- colSums(chain3 != 0)
# Diatom_chains_3 <- colSums(chain4 != 0)
# Ostracods <- colSums(ostra != 0)
# Copepods <- colSums(copepods != 0)
# Decapods <- colSums(decapod != 0)
# Echinoderms <- colSums(echino != 0)
# Eucampia_spp <- colSums(eucampia != 0)
# Jellies<- colSums(jellies != 0)
# Larvaceans <- colSums(larvae != 0)
# Noctiluca <- colSums(nocti != 0)
# Polychaetes <- colSums(polychaetes != 0)
# Trichodesmium_spp <- colSums(tricho != 0)
#
# # Parse the date-time string with ymd_hm()
# occ_datetime <- as.POSIXct(id_list[i], format="%Y%m%d_%H%M", tz="UTC")
# occ_datetime_str <- substr(id_list[i], 1, 13)
#
# row_df <- data.frame(date = occ_datetime, occ_datetime_str,
# Acantharea,
# Centric,
# Ceratium_spp,
# Chaetoceros,
# Chaetognaths,
# Diatom_chains_1,
# Diatom_chains_2,
# Diatom_chains_3,
# Ostracods,
# Copepods,
# Decapods,
# Echinoderms,
# Eucampia_spp,
# Jellies,
# Larvaceans,
# Noctiluca,
# Polychaetes,
# Trichodesmium_spp
# )
# rownames(row_df) <- i
#
# conc_occ_count <- rbind(conc_occ_count, row_df)
# }
#
# conc_occ_final <- arrange(conc_occ_count, date)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vazogU3RyaW5nbWF0Y2giCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgojIExvYWQgZGF0YSBmaWxlcwpgYGB7cn0KbGlicmFyeShkcGx5cikKCiMgc3BlY2lmeSB0aGUgZGlyZWN0b3J5IHdoZXJlIHRoZSBmaWxlcyBhcmUgbG9jYXRlZAojIEZvciBOT0FBIG1hY2hpbmVzCiMgZGlyX3BhdGggPC0gIi9Vc2Vycy9lbnJpcXVlLm1vbnRlcy9Hb29nbGUgRHJpdmUvTXkgRHJpdmUvR0RyaXZlL09DRURfQU9NTC9XU19jcnVpc2VzL3BsYW5rdG9uX2ltYWdpbmcvQ1BJQ1MvVFMuTWFzdGVyX3NlbGVjdGlvbiIKIyBGb3IgcGVyc29uYWwgbWFjaGluZQpkaXJfcGF0aCA8LSAifi9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1lbnJpcXVlbW9udGVzMDFAZ21haWwuY29tL015IERyaXZlL0dEcml2ZS9PQ0VEX0FPTUwvV1NfY3J1aXNlcy9wbGFua3Rvbl9pbWFnaW5nL0NQSUNTL1RTLk1hc3Rlcl9zZWxlY3Rpb24iCgojIG9idGFpbiBhIGxpc3Qgb2YgZmlsZSBuYW1lcyBpbiB0aGUgZGlyZWN0b3J5CmZpbGVfbmFtZXMgPC0gbGlzdC5maWxlcyhwYXRoID0gZGlyX3BhdGgsIHBhdHRlcm4gPSAiLnR4dCIsIGZ1bGwubmFtZXMgPSBUUlVFKQoKIyBsb29wIG92ZXIgZWFjaCBmaWxlIGFuZCBpbXBvcnQgdGhlIHRhYmxlcyAodXNlIHRoaXMgZm9yIERBVEVTKQpmb3IgKGZpbGUgaW4gZmlsZV9uYW1lcykgewogIHRhYmxlX25hbWUgPC0gZ3N1YigiLnR4dCIsICIiLCBiYXNlbmFtZShmaWxlKSkgIyBnZXQgdGhlIG5hbWUgb2YgdGhlIHRhYmxlIGZyb20gdGhlIGZpbGUgbmFtZQogIGFzc2lnbih0YWJsZV9uYW1lLCByZWFkLnRhYmxlKGZpbGUgPSBmaWxlLCBoZWFkZXIgPSBGQUxTRSwgc2VwID0gIlx0IikgJT4lCiAgICAgICAgICAgbXV0YXRlKGRhdGUgPSBhcy5QT1NJWGN0KHN1YnN0cihWMSwgc3RhcnQgPSAyNCwgc3RvcCA9IDM2KSwgZm9ybWF0PSIlWSVtJWRfJUglTSIsIHR6PSJVVEMiKSkpCn0KCiMgIyBsb29wIG92ZXIgZWFjaCBmaWxlIGFuZCBpbXBvcnQgdGhlIHRhYmxlcyAodXNlIHRoaXMgZm9yIFNUUklOR1MpCiMgZm9yIChmaWxlIGluIGZpbGVfbmFtZXMpIHsKIyAgIHRhYmxlX25hbWUgPC0gZ3N1YigiLnR4dCIsICIiLCBiYXNlbmFtZShmaWxlKSkgIyBnZXQgdGhlIG5hbWUgb2YgdGhlIHRhYmxlIGZyb20gdGhlIGZpbGUgbmFtZQojICAgYXNzaWduKHRhYmxlX25hbWUsIHJlYWQudGFibGUoZmlsZSA9IGZpbGUsIGhlYWRlciA9IEZBTFNFLCBzZXAgPSAiXHQiKSkKIyB9CgpgYGAKCgojIE1hdGNoIGZpbGUgbmFtZSB1c2luZyBEQVRFIHZhbHVlcwpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQoKZGlyX3BhdGgyIDwtICJ+L0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0dvb2dsZURyaXZlLWVucmlxdWVtb250ZXMwMUBnbWFpbC5jb20vTXkgRHJpdmUvR0RyaXZlL09DRURfQU9NTC9XU19jcnVpc2VzL3BsYW5rdG9uX2ltYWdpbmcvQ1BJQ1Mvd3NfY3J1aXNlX2N0ZCIKCmZpbGVfbmFtZSA8LSBsaXN0LmZpbGVzKHBhdGggPSBkaXJfcGF0aDIsIHBhdHRlcm4gPSAiY3RkX21ldGFfdjMuY3N2IiwgZnVsbC5uYW1lcyA9IFRSVUUpCmN0ZF9tZXRhIDwtIHJlYWQuY3N2KGZpbGVfbmFtZSwgZmlsbCA9IFRSVUUpCgojIFVTRSBXSVRIIGN0ZF9tZXRhX3YzLmNzdgpkdF9saXN0IDwtIGFzLlBPU0lYY3QocGFzdGUoY3RkX21ldGEkeWVhciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUwMmQiLCBjdGRfbWV0YSRtb250aCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlMDJkIiwgY3RkX21ldGEkZGF5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0ZF9tZXRhJHRpbWVfZ210KSwKICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICIlWSVtJWQgJUk6JU06JVMgJXAiLAogICAgICAgICAgICAgICAgICAgICAgdHogPSAiVVRDIikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBUaGlzIHNlY3Rpb24gZGV0ZWN0cyBzaG9ydCB0cmFuc2l0IHRpbWVzIGJldHdlZW4gc3RhdGlvbnMKCiMgQ2FsY3VsYXRlIHRpbWUgZGlmZmVyZW5jZXMgaW4gc2Vjb25kcyBiZXR3ZWVuIGNvbnNlY3V0aXZlIGR0X2xpc3Qgb2JqZWN0cwp0aW1lX2RpZmZlcmVuY2VzIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoZHRfbGlzdFstMV0sIGR0X2xpc3RbLWxlbmd0aChkdF9saXN0KV0sIHVuaXRzID0gInNlY3MiKSkKCiMgQ29udmVydCB0aW1lIGRpZmZlcmVuY2VzIGZyb20gc2Vjb25kcyB0byBtaW51dGVzCnRpbWVfZGlmZmVyZW5jZXNfbWlucyA8LSB0aW1lX2RpZmZlcmVuY2VzIC8gNjAKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBzaG93aW5nIHRoZSBvcmlnaW5hbCB0aW1lcyBhbmQgdGhlaXIgZGlmZmVyZW5jZXMgaW4gbWludXRlcwp0aW1lX2RpZmZfZGYgPC0gZGF0YS5mcmFtZSgKICBzdGFydF90aW1lID0gZHRfbGlzdFstbGVuZ3RoKGR0X2xpc3QpXSwKICBlbmRfdGltZSA9IGR0X2xpc3RbLTFdLAogIHRpbWVfZGlmZmVyZW5jZV9taW5zID0gdGltZV9kaWZmZXJlbmNlc19taW5zCikKCiMgZmluZCBDVEQgdGltZSBzdGFtcHMgb2YgY29uc2VjdXRpdmUgc3RhdGlvbnMgd2l0aGluIGxlc3MgdGhhbiAyMCBtaW4uIFRoaXMgd2lsbCBpZGVudGlmeSBDVEQgY2FzdHMgdGhhdCBhcmUgY2xvc2UgdG8gZWFjaCBvdGhlcgpzaG9ydF90X2lkeCA8LSB3aGljaCh0aW1lX2RpZmZfZGYkdGltZV9kaWZmZXJlbmNlX21pbnMgPCAyMCkKc2hvcnRfdGltZXN0YW1wcyA8LSBkdF9saXN0W3Nob3J0X3RfaWR4XQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBDcmVhdGUgZW1wdHkgZGF0YSBmcmFtZSB0byBzdG9yZSByZXN1bHRzCmNvbmNfb2NjX2ZpbmFsIDwtIGRhdGEuZnJhbWUoZGF0ZSA9IGNoYXJhY3RlcigpLCBjb3VudCA9IG51bWVyaWMoKSkKCiMgTGlzdCBvZiBjbGFzcyBvYmplY3RzIHRvIGJlIHByb2Nlc3NlZApjbGFzc19uYW1lcyA8LSBjKCJBY2FudGhhcmVhIiwgIkNlbnRyaWMiLCAiQ2VyYXRpdW0iLCAiQ2hhZXRvY2Vyb3MiLCAiQ2hhZXRvZ25hdGhzIiwgCiAgICAgICAgICAgICAgICAgIkNoYWluMiIsICJDaGFpbjMiLCAiT3N0cmFjb2RzIiwgIkNvcGVwb2RzIiwgIkRlY2Fwb2RzIiwgIkVjaGlub2Rlcm1zIiwgCiAgICAgICAgICAgICAgICAgIkd1aW5hcmRpYSIsICJKZWxsaWVzIiwgIkxhcnZhY2VhbnMiLCAiTmVvY2FseXB0cmVsbGEiLCAiTm9jdGlsdWNhIiwgCiAgICAgICAgICAgICAgICAgInBlbGxldHMiLCAiUG9seWNoYWV0cyIsICJQdGVyb3BvZHMiLCAiVHJpY2hvIikKCiMgdGltZSBidWZmZXIgYmVmb3JlIGFuZCBhZnRlciBDVEQgdGltZSBpbiBzZWNvbmRzIHNvIHRoYXQgQ1BJQ1MgcmVjb3JkcyBhcmUgbWF0Y2hlZCB0byBDVEQgdGltZXMuCnN0YXJ0IDwtIDEwICogNjAgCnN0b3AgPC0gMTAgKiA2MCAKCiMgSXRlcmF0ZSBvdmVyIGR0X2xpc3QgaW50ZXJ2YWxzCmZvciAoaSBpbiAxOmxlbmd0aChkdF9saXN0KSkgewogIAogICMgSW5pdGlhbGl6ZSBhIGxpc3QgdG8gc3RvcmUgY291bnRzIGZvciB0aGUgY3VycmVudCBpbnRlcnZhbAogIGNvdW50c19saXN0IDwtIGxpc3QoZGF0ZSA9IGR0X2xpc3RbaV0pCiAgCiAgIyBJdGVyYXRlIG92ZXIgZWFjaCBjbGFzcyBvYmplY3QgYW5kIHBlcmZvcm0gc3Vic2V0dGluZwogIGZvciAoY2xhc3NfbmFtZSBpbiBjbGFzc19uYW1lcykgewogICAgY2xhc3NfZGF0YSA8LSBnZXQocGFzdGUwKCJjbGFzcy4iLCBjbGFzc19uYW1lKSkgICMgRHluYW1pY2FsbHkgZ2V0IHRoZSBjbGFzcyBkYXRhIGZyYW1lCiAgICAKICAgIGlmIChpIDwgbGVuZ3RoKGR0X2xpc3QpKSB7CiAgICAgICMgU3Vic2V0dGluZyBmb3IgYWxsIGludGVydmFscyBleGNlcHQgdGhlIGxhc3Qgb25lCiAgICAgIHN1YnNldF9kYXRhIDwtIHN1YnNldChjbGFzc19kYXRhLCBkYXRlID49IGR0X2xpc3RbaV0tc3RhcnQgJiBkYXRlIDwgZHRfbGlzdFtpKzFdLXN0b3ApCiAgICB9IGVsc2UgewogICAgICAjIFN1YnNldHRpbmcgZm9yIHRoZSBsYXN0IGludGVydmFsOiBjYXB0dXJlIGFsbCBkYXRhIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgbGFzdCBkdF9saXN0CiAgICAgIHN1YnNldF9kYXRhIDwtIHN1YnNldChjbGFzc19kYXRhLCBkYXRlID49IGR0X2xpc3RbaV0tc3RhcnQpCiAgICB9CiAgICAKICAgIGNvdW50c19saXN0W1tjbGFzc19uYW1lXV0gPC0gbnJvdyhzdWJzZXRfZGF0YSkKICB9CiAgCiAgIyBDb252ZXJ0IGNvdW50c19saXN0IHRvIGEgZGF0YSBmcmFtZSBhbmQgYmluZCBpdCB0byB0aGUgcmVzdWx0CiAgcmVzdWx0IDwtIGFzLmRhdGEuZnJhbWUoY291bnRzX2xpc3QpCiAgY29uY19vY2NfZmluYWwgPC0gcmJpbmQoY29uY19vY2NfZmluYWwsIHJlc3VsdCkKfSAKCiMgQ29tYmluZSB3aXRoIGN0ZF9tZXRhCnRheGFfbWV0YSA8LSBjYmluZChjdGRfbWV0YSwgY29uY19vY2NfZmluYWwpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIENoZWNrIGZvciB1bmFjY291bnRlZCBDUElDUyByZWNvcmRzIAoKIyBJbml0aWFsaXplIGEgbGlzdCB0byBzdG9yZSB1bmFjY291bnRlZCBkYXRlcyBmb3IgZWFjaCBjbGFzcwp1bmFjY291bnRlZF9kYXRlc19saXN0IDwtIGxpc3QoKQoKIyBJdGVyYXRlIG92ZXIgZWFjaCBjbGFzcyBvYmplY3QKZm9yIChjbGFzc19uYW1lIGluIGNsYXNzX25hbWVzKSB7CiAgIyBHZXQgdGhlIGRhdGUtdGltZSBvYmplY3RzIGZyb20gdGhlIGN1cnJlbnQgY2xhc3MKICBzZWxfY2xhc3NfZGF0ZXMgPC0gZ2V0KHBhc3RlMCgiY2xhc3MuIiwgY2xhc3NfbmFtZSkpJGRhdGUKICAKICAjIEluaXRpYWxpemUgYSBsb2dpY2FsIHZlY3RvciB0byB0cmFjayB3aGV0aGVyIGVhY2ggY2xhc3MgZGF0ZSBpcyBhY2NvdW50ZWQgZm9yCiAgaXNfYWNjb3VudGVkX2ZvciA8LSByZXAoRkFMU0UsIGxlbmd0aChzZWxfY2xhc3NfZGF0ZXMpKQogIAogICMgQ2hlY2sgZWFjaCBjbGFzcyBkYXRlIGFnYWluc3QgdGhlIGludGVydmFscyBpbiBkdF9saXN0CiAgZm9yIChpIGluIDE6bGVuZ3RoKGR0X2xpc3QpKSB7CiAgICBpZiAoaSA8IGxlbmd0aChkdF9saXN0KSkgewogICAgICAjIENoZWNrIGFsbCBpbnRlcnZhbHMgZXhjZXB0IHRoZSBsYXN0IG9uZQogICAgICBpbnRlcnZhbF9zdGFydCA8LSBkdF9saXN0W2ldIC0gc3RhcnQKICAgICAgaW50ZXJ2YWxfZW5kIDwtIGR0X2xpc3RbaSArIDFdIC0gc3RvcAogICAgfSBlbHNlIHsKICAgICAgIyBMYXN0IGludGVydmFsIGNhcHR1cmVzIGFsbCBkYXRhIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgbGFzdCBkdF9saXN0CiAgICAgIGludGVydmFsX3N0YXJ0IDwtIGR0X2xpc3RbaV0gLSBzdGFydAogICAgICBpbnRlcnZhbF9lbmQgPC0gSW5mICAjIEVmZmVjdGl2ZWx5IG5vIHVwcGVyIGJvdW5kCiAgICB9CiAgICAKICAgICMgTWFyayBjbGFzcyBkYXRlcyB0aGF0IGZhbGwgd2l0aGluIHRoZSBjdXJyZW50IGludGVydmFsIGFzIGFjY291bnRlZCBmb3IKICAgIGlzX2FjY291bnRlZF9mb3IgPC0gaXNfYWNjb3VudGVkX2ZvciB8IChzZWxfY2xhc3NfZGF0ZXMgPj0gaW50ZXJ2YWxfc3RhcnQgJiBzZWxfY2xhc3NfZGF0ZXMgPCBpbnRlcnZhbF9lbmQpCiAgfQogIAogICMgU3Vic2V0IHRoZSBjbGFzcyBkYXRlcyB0aGF0IHdlcmUgbm90IGFjY291bnRlZCBmb3IKICB1bmFjY291bnRlZF9zZWxfY2xhc3NfZGF0ZXMgPC0gc2VsX2NsYXNzX2RhdGVzWyFpc19hY2NvdW50ZWRfZm9yXQogIAogICMgU3RvcmUgdGhlIHVuYWNjb3VudGVkIGRhdGVzIGluIHRoZSBsaXN0CiAgdW5hY2NvdW50ZWRfZGF0ZXNfbGlzdFtbY2xhc3NfbmFtZV1dIDwtIHVuYWNjb3VudGVkX3NlbF9jbGFzc19kYXRlcwp9CgojIFByaW50IG9yIHZpZXcgdGhlIHVuYWNjb3VudGVkIGRhdGVzIGZvciBlYWNoIGNsYXNzCmZvciAoY2xhc3NfbmFtZSBpbiBjbGFzc19uYW1lcykgewogIGNhdCgiVW5hY2NvdW50ZWQgZGF0ZXMgZm9yIGNsYXNzOiIsIGNsYXNzX25hbWUsICJcbiIpCiAgcHJpbnQodW5hY2NvdW50ZWRfZGF0ZXNfbGlzdFtbY2xhc3NfbmFtZV1dKQogIGNhdCgiXG4iKQp9CmBgYAoKIyAjIENhbGN1bGF0ZSBwbGFua3RvbiBjb25jZW50cmF0aW9uIHRpbWUgc2VyaWVzIHBlciBzdGF0aW9uCmBgYHtyfQojIENhbGN1bGF0ZSBzcGVjaWVzIGNvbmNlbnRyYXRpb24gKGNvdW50cy9tbCkgZm9yIGVhY2ggc3BlY2llcwoKIyBGb3Igem9vcGxhbmt0b24KdGF4YV9tZXRhX2NvbmNlbnRyYXRpb24gPC0gdGF4YV9tZXRhICU+JQogIG11dGF0ZShhY3Jvc3MoYyhBY2FudGhhcmVhLENoYWV0b2duYXRocyxPc3RyYWNvZHMsQ29wZXBvZHMsRGVjYXBvZHMsRWNoaW5vZGVybXMsSmVsbGllcywKICAgIExhcnZhY2VhbnMsUG9seWNoYWV0cyxQdGVyb3BvZHMpLCB+IC4vdG90YWxfdm9sX3NhbXBsZWQgKiAxZTYpKSAlPiUKICBzZWxlY3QoU3RhdGlvbiwgZGVjX2xhdCwgZGVjX2xvbiwgeWVhciwgbW9udGgsIGRhdGUsIEF2Zy5jaGwuYS4udWcuTC4sCiAgICAgICAgIHRlbXAuLmRlZ0MuLCBzYWxpbml0eSwgdG90YWxfdm9sX3NhbXBsZWQsCiAgICAgICAgIEFjYW50aGFyZWEsQ2hhZXRvZ25hdGhzLE9zdHJhY29kcyxDb3BlcG9kcyxEZWNhcG9kcyxFY2hpbm9kZXJtcywKICAgICAgICAgSmVsbGllcyxMYXJ2YWNlYW5zLFBvbHljaGFldHMsUHRlcm9wb2RzKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHRvdGFsX3ZvbF9zYW1wbGVkKSkKCiMgIyBUcmFuc2Zvcm0gdGF4YV9tZXRhX2NvbmNlbnRyYXRpb24gdG8gbG9uZyBmb3JtYXQKdGF4YV9tZXRhX2xvbmcgPC0gdGF4YV9tZXRhX2NvbmNlbnRyYXRpb24gJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKEFjYW50aGFyZWEsIENoYWV0b2duYXRocyxPc3RyYWNvZHMsQ29wZXBvZHMsRGVjYXBvZHMsCiAgICAgICAgICAgICAgICAgICAgICAgIEVjaGlub2Rlcm1zLCBKZWxsaWVzLCBMYXJ2YWNlYW5zLFBvbHljaGFldHMsIFB0ZXJvcG9kcyksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNwZWNpZXMiLCB2YWx1ZXNfdG8gPSAic3BlY2llc19jb25jZW50cmF0aW9uIikKCiMgIyBGb3IgcGh5dG9wbGFua3RvbgojIHRheGFfbWV0YV9jb25jZW50cmF0aW9uIDwtIHRheGFfbWV0YSAlPiUKIyAgIG11dGF0ZShhY3Jvc3MoYyhDZW50cmljLENlcmF0aXVtLENoYWV0b2Nlcm9zLENoYWluMixDaGFpbjMsR3VpbmFyZGlhLE5lb2NhbHlwdHJlbGxhLAojICAgICAgICAgICAgICAgICAgIE5vY3RpbHVjYSxUcmljaG8pLCB+IC4vdG90YWxfdm9sX3NhbXBsZWQgKiAxZTYpKSAlPiUKIyAgIHNlbGVjdChTdGF0aW9uLCBkZWNfbGF0LCBkZWNfbG9uLCB5ZWFyLCBtb250aCwgZGF0ZSwgQXZnLmNobC5hLi51Zy5MLiwKIyAgICAgICAgICB0ZW1wLi5kZWdDLiwgc2FsaW5pdHksdG90YWxfdm9sX3NhbXBsZWQsCiMgICAgICAgICAgQ2VudHJpYyxDZXJhdGl1bSxDaGFldG9jZXJvcyxDaGFpbjIsQ2hhaW4zLEd1aW5hcmRpYSxOZW9jYWx5cHRyZWxsYSwKIyAgICAgICAgICAgICAgICAgICBOb2N0aWx1Y2EsVHJpY2hvKSAlPiUKIyAgIGZpbHRlcighaXMubmEodG90YWxfdm9sX3NhbXBsZWQpKQojIAojICMgIyBUcmFuc2Zvcm0gdGF4YV9tZXRhX2NvbmNlbnRyYXRpb24gdG8gbG9uZyBmb3JtYXQKIyB0YXhhX21ldGFfbG9uZyA8LSB0YXhhX21ldGFfY29uY2VudHJhdGlvbiAlPiUKIyAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhDZW50cmljLENlcmF0aXVtLENoYWV0b2Nlcm9zLENoYWluMixDaGFpbjMsR3VpbmFyZGlhLE5lb2NhbHlwdHJlbGxhLAojICAgICAgICAgICAgICAgICAgIE5vY3RpbHVjYSxUcmljaG8pLAojICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNwZWNpZXMiLCB2YWx1ZXNfdG8gPSAic3BlY2llc19jb25jZW50cmF0aW9uIikKCiMgRmlsdGVyIHRoZSBkYXRhIGZvciBTdGF0aW9ucwojIHN0YXRpb25fbGlzdF9mayA8LSBjKCJXUyIsIjIxL0xLIiwiTVIiLCIxNiIsIjE4IiwiMTAiLCIxMiIsIjkuNSIsIjkiLCI3IiwiMiIpCiMgc3RhdGlvbl9saXN0X3NyIDwtIGMoIjY4IiwiNjUiLCI2NCIsIjYwIiwiNTgiLCI1Ny4zIiwiNTcuMiIsIjU3LjEiLCI1NyIsIjU2IiwiNTUiLCI1NCIsIjUzIiwiNTEiLAojICAgICAgICAgICAgICAgICAgICI0OSIsIjQ3IiwiNDUiLCI0MSIsIjMwIiwiMzEiLCIzMyIpCiMgc3RhdGlvbl9saXN0X2NhbCA8LSBjKCJDQUw1IiwiQ0FMNCIsIkNBTDMiLCJDQUwyIiwiQ0FMMSIsIlJQMSIsIlJQMiIsIlJQMyIsIlJQNCIsIkdQNSIsIkJHNCIsIkJHMyIsCiMgICAgICAgICAgICAgICAgICAgIkJHMiIsIkJHMSIsIkJHNiIsICJCRzciKQojIHN0YXRpb25fbGlzdF92bCA8LSBjKCJWMSIsIlYyIiwiVjMiLCJWNCIsIlY1IiwiVjYiLCJWNyIsIlY4IiwiVjkiLCJMMSIsIkwzIiwiTDUiLCJMNyIsIkw5IikKIyBzdGF0aW9uX2xpc3RfdGIgPC0gYygiQU1JOSIsIkFNSTgiLCJBTUk3IiwiQU1JNiIsIkFNSTUiLCJBTUk0IiwiQU1JMyIsIkFNSTIiLCJBTUkxIiwiVEIxIiwiVEIyIiwKIyAgICAgICAgICAgICAgICAgICAiVEIzIiwiVEI0IiwiVEI1IiwiVEIxMCIsIkNXNCIsIkNXMyIsIkNXMiIsIkNXMSIpCiMgZmlsdGVyZWRfdGF4YV9tZXRhX2xvbmcgPC0gdGF4YV9tZXRhX2xvbmcgJT4lCiAgIyBmaWx0ZXIoU3RhdGlvbiAlaW4lIHN0YXRpb25fbGlzdF9maykKCiMgV2l0aG91dCBmaWx0ZXJpbmcgcGVyIGdyb3VwIG9mIHN0YXRpb25zIGJ1dCBsb29raW5nIGF0IHRoZSBlbnRpcmUgcmVnaW9uCmZpbHRlcmVkX3RheGFfbWV0YV9sb25nIDwtIHRheGFfbWV0YV9sb25nCgojIENhbGN1bGF0ZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2Ygc3BlY2llcyBjb25jZW50cmF0aW9uIGZvciBlYWNoIGRhdGUKc3VtbWFyeV9kYXRhIDwtIGZpbHRlcmVkX3RheGFfbWV0YV9sb25nICU+JQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBzcGVjaWVzKSAlPiUKICBzdW1tYXJpc2UobWVhbl9jb25jZW50cmF0aW9uID0gbWVhbihzcGVjaWVzX2NvbmNlbnRyYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHNkX2NvbmNlbnRyYXRpb24gPSBzZChzcGVjaWVzX2NvbmNlbnRyYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGVhcmxpZXN0X2RheSA9IG1pbihhcy5udW1lcmljKGZvcm1hdChkYXRlLCAiJWQiKSksIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKQoKIyBDb21iaW5lIHllYXIgYW5kIG1vbnRoIGNvbHVtbnMgaW50byBhIHNpbmdsZSBkYXRlIGNvbHVtbgpzdW1tYXJ5X2RhdGEkZGF0ZSA8LSBhcy5EYXRlKHBhc3RlKHN1bW1hcnlfZGF0YSR5ZWFyLCBzdW1tYXJ5X2RhdGEkbW9udGgsIHN1bW1hcnlfZGF0YSRlYXJsaWVzdF9kYXksIHNlcCA9ICItIikpIAoKIyBjdXN0b21fcGFsX2hleDIgPC0gYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJywnI2E2NTYyOCcsJyNmNzgxYmYnKQpjdXN0b21fcGFsX2hleDIgPC0gYygnZGFya3R1cnF1b2lzZScsJ3JlZCcsJyM0ZGFmNGEnLCdzbGF0ZWdyYXk0Jywnb3JhbmdlJywnZG9kZ2VyYmx1ZScsJ3B1cnBsZScsICJ5ZWxsb3ciLCJwaW5rIiwidmlvbGV0IikKCiMgQWNhbnRoYXJlYSA9IGRhcmt0dXJxdW9pc2UKIyBDb3BlcG9kcyA9IHJlZAojIGVjaGlub3MgPSAjNGRhZjRhCiMgSmVsbGllcyA9IHNsYXRlZ3JheTQKIyBMYXJ2YWNlYW5zID0gb3JhbmdlCiMgUG9seWNoYWV0ZXMgPSBkb2RnZXJibHVlCiMgUHRlcm9wb2RzID0gcHVycGxlCgojICMgQ2hlY2sgZG9taW5hbmNlIG9mIGdyb3VwcyBieSBjYWxjdWxhdGluZyB0aGUgb3ZlcmFsbCBtZWFuIAojIHRlc3QgPC0gc3VtbWFyeV9kYXRhICU+JSBmaWx0ZXIoc3BlY2llcyA9PSAiUG9seWNoYWV0ZXMiKSAlPiUgc3VtbWFyaXplKGF2ZyA9IG1lYW4obWVhbl9jb25jZW50cmF0aW9uKSkKIyBtZWFuKHRlc3QkYXZnKQoKIyBQbG90IHRpbWUgc2VyaWVzIG9mIG1lYW4rc2QgcGxhbnRvbiBjb25jZW50cmF0aW9uIHBlciBncm91cCBvZiBzaXRlcwp6eiA8LSBnZ3Bsb3Qoc3VtbWFyeV9kYXRhLCBhZXMoeCA9IGRhdGUsIHkgPSBtZWFuX2NvbmNlbnRyYXRpb24sIGZpbGwgPSBzcGVjaWVzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWxfaGV4MikgKwogICMgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IDAsIHltYXggPSBtZWFuX2NvbmNlbnRyYXRpb24gKyBzZF9jb25jZW50cmF0aW9uKSwKICAjICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHdpZHRoID0gMC4yKSArCiAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIk1lYW4gU3BlY2llcyBDb25jZW50cmF0aW9uIiwgZmlsbCA9ICJTcGVjaWVzIikgKwogIHRoZW1lX21pbmltYWwoKQp6egoKIyBGaWx0ZXIgc3VtbWFyeV9kYXRhIGZvciBzZWxlY3RlZCBvbmx5CiMgQWNhbnRoYXJlYSwgQ29wZXBvZHMsIEVjaGlub2Rlcm1zLCBKZWxsaWVzLCBMYXJ2YWNlYW5zLCBDaGFldG9nbmF0aHMsIFBvbHljaGFldGVzLCBQdGVyb3BvZHMKIyBDZW50cmljLENlcmF0aXVtLENoYWV0b2Nlcm9zLENoYWluMixDaGFpbjIsR3VpbmFyZGlhLE5lb2NhbHlwdHJlbGxhLE5vY3RpbHVjYSxUcmljaG9kZXNtaXVtCgpzZWxlY3RlZF9ncm91cCA8LSAiUHRlcm9wb2RzIgoKc3VtbWFyeV9zZWxlY3RlZCA8LSBmaWx0ZXJlZF90YXhhX21ldGFfbG9uZyAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSBzZWxlY3RlZF9ncm91cCkgJT4lCiAgZmlsdGVyKHNwZWNpZXNfY29uY2VudHJhdGlvbiA+IDApICU+JQogIGdyb3VwX2J5KHllYXIsIG1vbnRoKSAlPiUKICBtdXRhdGUoZWFybGllc3RfZGF5ID0gbWluKGFzLm51bWVyaWMoZm9ybWF0KGRhdGUsICIlZCIpKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShkYXRlID0gYXMuRGF0ZShwYXN0ZSh5ZWFyLCBtb250aCwgZWFybGllc3RfZGF5LCBzZXAgPSAiLSIpKSkgJT4lCiAgc2VsZWN0KC1lYXJsaWVzdF9kYXkpICAjIE9wdGlvbmFsbHksIHJlbW92ZSB0aGUgJ2VhcmxpZXN0X2RheScgY29sdW1uIGlmIG5vdCBuZWVkZWQKCiMgQ3JlYXRlIHRoZSB0aW1lIHNlcmllcyBib3hwbG90CiAgc2VsX2JveCA8LSAgZ2dwbG90KHN1bW1hcnlfc2VsZWN0ZWQsIGFlcyh4ID0gYXMuZmFjdG9yKGRhdGUpLCB5ID0gc3BlY2llc19jb25jZW50cmF0aW9uKSkgKwogICAgZ2VvbV9ib3hwbG90KGZpbGwgPSAid2hpdGUiLCBub3RjaCA9IEZBTFNFLCBvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgICMgZ2VvbV92aW9saW4oZmlsbCA9ICJsaWdodGdyZXkiLCBjb2xvciA9ICJOQSIsIGFscGhhID0gMC43KSArCiAgICAjIGdlb21faml0dGVyKGFlcyhjb2xvciA9IGZhY3RvcihTdGF0aW9uKSwgc2l6ZSA9IHRlbXAuLmRlZ0MuKSwgYWxwaGEgPSAwLjkpICsKICAgICMgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjI1LCBhZXMoY29sb3IgPSB0ZW1wLi5kZWdDLiwgc2l6ZSA9IHNhbGluaXR5KSwgYWxwaGEgPSAwLjYpICsgIyB3aXRoIHNhbGluaXR5IGluY2x1ZGVkCiAgICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMjUsIGFlcyhjb2xvciA9IHRlbXAuLmRlZ0MuKSwgc2l6ZSA9IDMsIGFscGhhID0gMC42KSArCiAgICBsYWJzKHggPSAiRGF0ZSIsIHkgPSBleHByZXNzaW9uKCJEZW5zaXR5IChvcmcuIG0iXiItMyJ+IikiKSkgKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG5hbWUgPSAiVGVtcGVyYXR1cmUgKMKwQykiLCBvcHRpb24gPSAiaW5mZXJubyIpICsKICAgICMgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiU2FsaW5pdHkiLCAjIHdpdGggc2FsaW5pdHkgaW5jbHVkZWQKICAgICMgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMzAsIDM4KSwKICAgICMgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMzAsIDMyLCAzNCwgMzYsIDM4KSwKICAgICMgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlID0gYygxLCA0KSkgKwogICAgeWxpbSgwLCAzMDAwMCkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgY29sb3IgPSAiYmxhY2siKSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgY29sb3IgPSAiYmxhY2siKSkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG9yID0gImJsYWNrIikpICsKICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpKSAKICBzZWxfYm94CgojIFNhdmUgZmlndXJlIGFzIGEgc3ZnIGZpbGUgIApnZ3NhdmUocGFzdGUwKCJjb25jX3RpbWUtc2VyaWVzXyIsIHNlbGVjdGVkX2dyb3VwLCAiLnN2ZyIpLCBwbG90ID0gc2VsX2JveCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZGV2aWNlID0gInN2ZyIpCiAgCiMgIyBQbG90IGNvbmNlbnRyYXRpb24gdGltZSBzZXJpZXMgZm9yIGFsbCBzZWxlY3RlZCBzaXRlcwojIGtrIDwtIGdncGxvdChzdW1tYXJ5X3NlbGVjdGVkLCBhZXMoeCA9IGRhdGUsIHkgPSBzcGVjaWVzX2NvbmNlbnRyYXRpb24sIHNoYXBlID0gZmFjdG9yKFN0YXRpb24pKSkgKwojICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIlNwZWNpZXMgY29uY2VudHJhdGlvbiAob3JnLm0tMykiKSArCiMgICBnZW9tX3BvaW50KGFlcyhzaXplID0gdGVtcC4uZGVnQy4pLCBmaWxsID0gImRhcmtncmV5IikgKyAjIG9yIGNvbG91ciA9IGZhY3RvcihTdGF0aW9uKQojICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMCwgMSwgMiwgMywgNCwgNSwgNikpCiMga2sKCiMga2sgPC0gZ2dwbG90KHN1bW1hcnlfc2VsZWN0ZWQsIGFlcyh4ID0gZGF0ZSwgeSA9IHNwZWNpZXNfY29uY2VudHJhdGlvbiwgY29sb3VyID0gZmFjdG9yKFN0YXRpb24pKSkgKwojICAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIlNwZWNpZXMgY29uY2VudHJhdGlvbiAob3JnLm0tMykiKSArCiMgICBnZW9tX3BvaW50KGFlcyhzaXplID0gdGVtcC4uZGVnQy4pLCBhbHBoYSA9IDAuNykgKyAjIG9yIGNvbG91ciA9IGZhY3RvcihTdGF0aW9uKSArCiMgICAjIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCA0KSwgc2UgPSBGQUxTRSkgKyAjIEFkZCBwb2x5bm9taWFsIGZpdCBsaW5lCiMgICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCiMga2sKICAKIyAjIEZpbmQgdGhlIGluZGV4IG9mIHRoZSBsYXN0IHJvdyB3aXRoIGRhdGUgPT0gJzIwMjMtMDEtMTUnIGFuZCBhZGQgYSBkdW1teSByb3cgZm9yIG1pc3NpbmcgZGF0ZXMKIyBuZXdfcm93IDwtIHRpYmJsZShTdGF0aW9uID0gTkEsIGRlY19sYXQgPSBOQSwgZGVjX2xvbiA9IE5BLCB5ZWFyID0gTkEsCiMgICAgICAgICAgICAgICAgICAgbW9udGggPSBOQSwgZGF0ZSA9IGFzLkRhdGUoJzIwMjMtMDMtMTUnKSwgQXZnLmNobC5hLi51Zy5MLiA9IE5BLAojICAgICAgICAgICAgICAgICAgIHRlbXAuLmRlZ0MuID0gTkEsIHNhbGluaXR5ID0gTkEsIHNwZWNpZXMgPSBOQSwgc3BlY2llc19jb25jZW50cmF0aW9uID0gTkEpCiMgbGFzdF9pbmRleCA8LSBtYXgod2hpY2goc3VtbWFyeV9zZWxlY3RlZCRkYXRlID09IGFzLkRhdGUoJzIwMjMtMDEtMTUnKSkpCiMgc3VtbWFyeV9zZWxlY3RlZCA8LSBiaW5kX3Jvd3MoCiMgICAgIHN1bW1hcnlfc2VsZWN0ZWRbMTpsYXN0X2luZGV4LCBdLAojICAgICBuZXdfcm93LAojICAgICBzdW1tYXJ5X3NlbGVjdGVkWyhsYXN0X2luZGV4ICsgMSk6bnJvdyhzdW1tYXJ5X3NlbGVjdGVkKSwgXQojICAgKQogIApgYGAKCiMgIyBDYWxjdWxhdGVzIHRvdGFsIHBsYW5rdG9uIGNvbmNlbnRyYXRpb25zIGFnZ3JlZ2F0aW5nIGRhdGEgZnJvbSBzZWxlY3RlZCBzdGF0aW9ucyAoZWcgRkspCmBgYHtyfQojIENhbGN1bGF0ZSBwbGFua3RvbiBjb25jZW50cmF0aW9uIGZvciBhbGwgc3BlY2llcyBzdW1tZWQgdXAKIyBGb3IgUGh5dG8KdGF4YV9tZXRhX2NvbmNlbnRyYXRpb25fYWxsIDwtIHRheGFfbWV0YSAlPiUKICBtdXRhdGUodG90YWxfY29uY2VudHJhdGlvbiA9ICgKICAgIENlbnRyaWMgKyBDZXJhdGl1bSArIENoYWV0b2Nlcm9zICsgQ2hhaW4yICsgQ2hhaW4zICsgR3VpbmFyZGlhICsgTmVvY2FseXB0cmVsbGEgKwogICAgTm9jdGlsdWNhICsgVHJpY2hvKSAvIHRvdGFsX3ZvbF9zYW1wbGVkICogMWU2KSAlPiUKICBzZWxlY3QoU3RhdGlvbiwgZGVjX2xhdCwgZGVjX2xvbiwgeWVhciwgbW9udGgsIGRhdGUsIEF2Zy5jaGwuYS4udWcuTC4sCiAgICAgICAgIHRlbXAuLmRlZ0MuLCBzYWxpbml0eSwgdG90YWxfdm9sX3NhbXBsZWQsIHRvdGFsX2NvbmNlbnRyYXRpb24pICU+JQogIGZpbHRlcighaXMubmEodG90YWxfdm9sX3NhbXBsZWQpKQoKIyAjIEZvciBab29wbGFua3RvbgojIHRheGFfbWV0YV9jb25jZW50cmF0aW9uX2FsbCA8LSB0YXhhX21ldGEgJT4lCiMgICBtdXRhdGUodG90YWxfY29uY2VudHJhdGlvbiA9ICgKIyAgICAgQWNhbnRoYXJlYSArIENoYWV0b2duYXRocyArIE9zdHJhY29kcyArIENvcGVwb2RzICsgRGVjYXBvZHMgKyBFY2hpbm9kZXJtcyArIEplbGxpZXMgKwojICAgICBMYXJ2YWNlYW5zICsgUG9seWNoYWV0cyArIFB0ZXJvcG9kcykgLyB0b3RhbF92b2xfc2FtcGxlZCAqIDFlNikgJT4lCiMgICBzZWxlY3QoU3RhdGlvbiwgZGVjX2xhdCwgZGVjX2xvbiwgeWVhciwgbW9udGgsIGRhdGUsIEF2Zy5jaGwuYS4udWcuTC4sCiMgICAgICAgICAgdGVtcC4uZGVnQy4sIHNhbGluaXR5LCB0b3RhbF92b2xfc2FtcGxlZCwgdG90YWxfY29uY2VudHJhdGlvbikgJT4lCiMgICBmaWx0ZXIoIWlzLm5hKHRvdGFsX3ZvbF9zYW1wbGVkKSkKCiMgRmlsdGVyIHRoZSBkYXRhIGZvciBTdGF0aW9ucwpzdGF0aW9uX2xpc3RfZmsgPC0gYygiV1MiLCIyMS9MSyIsIk1SIiwiMTYiLCIxOCIsIjEwIiwiMTIiLCI5LjUiLCI5IiwiNyIsIjIiKQpmaWx0ZXJlZF90YXhhX2NvbmNfYWxsIDwtIHRheGFfbWV0YV9jb25jZW50cmF0aW9uX2FsbCAlPiUKICBmaWx0ZXIoU3RhdGlvbiAlaW4lIHN0YXRpb25fbGlzdF9maykKCiMgQWdncmVnYXRlIHRvdGFsIGNvbmNlbnRyYXRpb24gYW5kIHRvdGFsIHZvbHVtZSBzYW1wbGVkIHBlciB5ZWFyIGFuZCBtb250aAphZ2dyZWdhdGVkX2NvbmNlbnRyYXRpb24gPC0gZmlsdGVyZWRfdGF4YV9jb25jX2FsbCAlPiUKICBncm91cF9ieSh5ZWFyLCBtb250aCkgJT4lCiAgc3VtbWFyaXNlKAogICAgdG90YWxfY291bnRzID0gc3VtKHRvdGFsX2NvbmNlbnRyYXRpb24gKiB0b3RhbF92b2xfc2FtcGxlZCAvIDFlNiwgbmEucm0gPSBUUlVFKSwgIyBTdW0gdXAgYWxsIGNvdW50cwogICAgdG90YWxfdm9sX3NhbXBsZWQgPSBzdW0odG90YWxfdm9sX3NhbXBsZWQsIG5hLnJtID0gVFJVRSksICMgU3VtIHVwIGFsbCB2b2x1bWUgc2FtcGxlZAogICAgbWVhbl90ZW1wX2RlZ0MgPSBtZWFuKHRlbXAuLmRlZ0MuLCBuYS5ybSA9IFRSVUUpLCAjIENhbGN1bGF0ZSBtZWFuIHRlbXBlcmF0dXJlCiAgICBtZWFuX3NhbGluaXR5ID0gbWVhbihzYWxpbml0eSwgbmEucm0gPSBUUlVFKSwgIyBDYWxjdWxhdGUgbWVhbiBzYWxpbml0eQogICAgbWVhbl9jaGxhID0gbWVhbihBdmcuY2hsLmEuLnVnLkwuLCBuYS5ybSA9IFRSVUUpIAogICkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSh0b3RhbF9jb25jZW50cmF0aW9uID0gKHRvdGFsX2NvdW50cyAvIHRvdGFsX3ZvbF9zYW1wbGVkKSAqIDFlNikgIyBSZWNhbGN1bGF0ZSB0aGUgY29uY2VudHJhdGlvbgoKIyBDcmVhdGUgYSBEYXRlIGNvbHVtbiBmb3IgcGxvdHRpbmcgcHVycG9zZXMKYWdncmVnYXRlZF9jb25jZW50cmF0aW9uIDwtIGFnZ3JlZ2F0ZWRfY29uY2VudHJhdGlvbiAlPiUKICBtdXRhdGUoeWVhcl9tb250aCA9IGFzLkRhdGUocGFzdGUoeWVhciwgbW9udGgsICIwMSIsIHNlcCA9ICItIikpKQoKIyBDcmVhdGUgdGhlIHRpbWUgc2VyaWVzIHBsb3QKY29uY2VudHJhdGlvbl90cyA8LSBnZ3Bsb3QoYWdncmVnYXRlZF9jb25jZW50cmF0aW9uLCBhZXMoeCA9IHllYXJfbW9udGgpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gdG90YWxfY29uY2VudHJhdGlvbiksIGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKyAjIExpbmUgcGxvdCBmb3IgdG90YWwgY29uY2VudHJhdGlvbgogIGdlb21fcG9pbnQoYWVzKHkgPSB0b3RhbF9jb25jZW50cmF0aW9uKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDIpICsgICMgUG9pbnRzIGZvciB0b3RhbCBjb25jZW50cmF0aW9uCiAgIyBnZW9tX2xpbmUoYWVzKHkgPSAobWVhbl90ZW1wX2RlZ0MgLSAyMCkgLyAoMzUgLSAyMCkgKiBtYXgodG90YWxfY29uY2VudHJhdGlvbikpLCAKICAjICAgICAgICAgICBjb2xvciA9ICJvcmFuZ2UiLCBzaXplID0gMSkgKyAgIyBMaW5lIHBsb3QgZm9yIHRlbXBlcmF0dXJlIChub3JtYWxpemVkKQogIGxhYnModGl0bGUgPSAiVG90YWwgUGh5dG9wbGFua3RvbiBDb25jZW50cmF0aW9uIFRpbWUgU2VyaWVzIiwKICAgICAgIHggPSAiRGF0ZSIsCiAgICAgICB5ID0gZXhwcmVzc2lvbigiVG90YWwgQ29uY2VudHJhdGlvbiAob3JnL20iXjN+IikiKSkgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgZGF0ZV9sYWJlbHMgPSAiJWIgJVkiKSArICAjIFNob3cgdGlja3MgZm9yIGV2ZXJ5IG1vbnRoCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbmFtZSA9IGV4cHJlc3Npb24oIlRvdGFsIENvbmNlbnRyYXRpb24gKG9yZy9tIl4zfiIpIiksICAgICAgICAgICAgIyBQcmltYXJ5IHktYXhpcyBsYWJlbAogICAgIyBzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqICgzNSAtIDIwKSAvIG1heChhZ2dyZWdhdGVkX2NvbmNlbnRyYXRpb24kdG90YWxfY29uY2VudHJhdGlvbikgKyAyMCwgCiAgICAjICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJUZW1wZXJhdHVyZSAowrBDKSIsIAogICAgIyAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgyMCwgMzUsIGJ5ID0gNSkpICAjIFNlY29uZGFyeSB5LWF4aXMgbGFiZWwKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICMgYXhpcy50aXRsZS55LnJpZ2h0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIm9yYW5nZSIpLCAgIyBDb2xvciB0aGUgc2Vjb25kYXJ5IHktYXhpcyBsYWJlbAogICAgIyBheGlzLmxpbmUueS5yaWdodCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJvcmFuZ2UiKSwgICAgIyBDb2xvciB0aGUgc2Vjb25kYXJ5IHktYXhpcyBsaW5lICAgCiAgICAjIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAjIFJlbW92ZSBtYWpvciBncmlkIGxpbmVzCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgIyBSZW1vdmUgbWlub3IgZ3JpZCBsaW5lcwogICAgIyBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCkgICAgICAgIyBSZW1vdmUgcGFuZWwgYm9yZGVyIGlmIG5lY2Vzc2FyeQogICkKCiMgUHJpbnQgdGhlIHBsb3QKY29uY2VudHJhdGlvbl90cwpgYGAKCiMgIyBDYWxjdWxhdGUgcGxhbmt0b24gY29uY2VudHJhdGlvbnMgcGVyIHNlYXNjYXBlIGNsYXNzCmBgYHtyfQpzcHBfZGYgPC0gdGF4YV9tZXRhWyAsIGMoIlg4LmRheS5zZWFzY2FwZXMiLCAidG90YWxfdm9sX3NhbXBsZWQiLCAiZGF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiQWNhbnRoYXJlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiQ29wZXBvZHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkVjaGlub2Rlcm1zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJKZWxsaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJMYXJ2YWNlYW5zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJQb2x5Y2hhZXRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFldG9nbmF0aHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIlB0ZXJvcG9kcyIpXQoKIyBzcHBfZGYgPC0gdGF4YV9tZXRhWyAsIGMoIlg4LmRheS5zZWFzY2FwZXMiLCAidG90YWxfdm9sX3NhbXBsZWQiLCAiZGF0ZSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJDZXJhdGl1bSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFldG9jZXJvcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFpbjIiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhaW4zIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIkd1aW5hcmRpYSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJOZW9jYWx5cHRyZWxsYSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJUcmljaG8iKV0KCiMgUmVtb3ZlIHJvd3Mgd2l0aCBOYU4gdmFsdWVzIGluIFg4LmRheS5zZWFzY2FwZXMgYW5kIHRvdGFsX3ZvbF9zYW1wbGVkCnNwcF9kZiA8LSBzdWJzZXQoc3BwX2RmLCAhaXMubmEoWDguZGF5LnNlYXNjYXBlcykgJiAhaXMubmEodG90YWxfdm9sX3NhbXBsZWQpKQoKIyBDYWxjdWxhdGUgdG90YWwgY291bnRzIHBlciBzcGVjaWVzIHdpdGhpbiBlYWNoIFg4LmRheS5zZWFzY2FwZXMgY2F0ZWdvcnkKc3BwX2NvdW50X3Blcl9zZWFzY2FwZSA8LSBzcHBfZGYgJT4lCiAgZ2F0aGVyKGtleSA9ICJzcGVjaWVzIiwgdmFsdWUgPSAiY291bnQiLCAtKFg4LmRheS5zZWFzY2FwZXM6ZGF0ZSkpICU+JQogIGdyb3VwX2J5KFg4LmRheS5zZWFzY2FwZXMsIHNwZWNpZXMpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9jb3VudCA9IHN1bShjb3VudCkpICU+JQogIHVuZ3JvdXAoKQoKIyBDYWxjdWxhdGUgdG90YWwgdm9sdW1lIHNhbXBsZWQgcGVyIFg4LmRheS5zZWFzY2FwZXMgY2F0ZWdvcnkKdG90YWxfdm9sX3Blcl9zZWFzY2FwZSA8LSBzcHBfZGYgJT4lCiAgZ3JvdXBfYnkoWDguZGF5LnNlYXNjYXBlcykgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3ZvbF9zYW1wbGVkID0gc3VtKHRvdGFsX3ZvbF9zYW1wbGVkKSkKCiMgTWVyZ2UgdG90YWwgY291bnRzIGFuZCB0b3RhbCB2b2x1bWUgZGF0YSBmcmFtZXMKc3BwX2NvbmNlbnRyYXRpb24gPC0gbWVyZ2Uoc3BwX2NvdW50X3Blcl9zZWFzY2FwZSwgdG90YWxfdm9sX3Blcl9zZWFzY2FwZSwgYnkgPSAiWDguZGF5LnNlYXNjYXBlcyIpCgojIENhbGN1bGF0ZSBzcGVjaWVzIHBlciBjdWJpYyBtZXRlcjogbWlnaHQgYmUgbWlzbGVhZGluZyBzaW5jZSBpdCBpbnRlZ3JhdGVzIGFsbCBjb3VudHMgYW5kIHNhbXBsZWQgdm9sdW1lcyBhY3Jvc3MgY3J1aXNlcyB0byBjYWxjdWxhdGUgY29uY2VudHJhdGlvbnMuIEl0IGlzIGxpa2VseSBiZXR0ZXIgdG8gdXNlIGF2ZXJhZ2UgY29uY2VudHJhdGlvbnMgYXMgYmVsb3cuCnNwcF9jb25jZW50cmF0aW9uJHNwZWNpZXNfcGVyX2N1YmljX21ldGVyIDwtIHNwcF9jb25jZW50cmF0aW9uJHRvdGFsX2NvdW50IC8gc3BwX2NvbmNlbnRyYXRpb24kdG90YWxfdm9sX3NhbXBsZWQgKiAxZTYKCiMgIyBTZWxlY3QgZGVzaXJlZCBzZWFzY2FwZXMgYW5kIHJlb3JkZXIgY2F0ZWdvcmllcyBpbiBYIGF4aXMKc3BwX2NvbmNlbnRyYXRpb24kWDguZGF5LnNlYXNjYXBlcyA8LSBmYWN0b3Ioc3BwX2NvbmNlbnRyYXRpb24kWDguZGF5LnNlYXNjYXBlcywgbGV2ZWxzID0gYygiMyIsICI1IiwgIjciLCAiMTEiLCAiMTMiLCAiMTUiLCIyMSIsIjI3IikpCgojIEZpbHRlciBvdXQgc2Vhc2NhcGUgY2xhc3MgYXMgZGVzaXJlZAojIGV4Y2x1ZGVfY2xhc3NlcyA8LSBjKDUsIDcsIDExKQojIHNwcF9jb25jZW50cmF0aW9uIDwtIHNwcF9jb25jZW50cmF0aW9uWyFzcHBfY29uY2VudHJhdGlvbiRYOC5kYXkuc2Vhc2NhcGVzICVpbiUgZXhjbHVkZV9jbGFzc2VzLCBdCgpjdXN0b21fcGFsX2hleDIgPC0gYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJywnI2E2NTYyOCcsJyNmNzgxYmYnKQoKIyBDcmVhdGUgdGhlIHN0YWNrIHBsb3QKY29uY2VudHJhdGlvbl9zdGFja3Bsb3QgPC0gZ2dwbG90KHNwcF9jb25jZW50cmF0aW9uLCBhZXMoeCA9IFg4LmRheS5zZWFzY2FwZXMsIHkgPSBzcGVjaWVzX3Blcl9jdWJpY19tZXRlciwgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fcGFsX2hleDIpICsKICBsYWJzKHggPSAiU2Vhc2NhcGUgY2xhc3MiLCB5ID0gIlNwZWNpZXMgY29uY2VudHJhdGlvbiAob3JnLiBtIl4iLTMifiIpIikgKwp0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksICAjIFNldCBYLWF4aXMgbGFiZWwgZm9udCBzaXplCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkKY29uY2VudHJhdGlvbl9zdGFja3Bsb3QKCiMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2VzCnNwcF9jb25jZW50cmF0aW9uX3BlcmNlbnQgPC0gc3BwX2NvbmNlbnRyYXRpb24gJT4lCiAgZ3JvdXBfYnkoWDguZGF5LnNlYXNjYXBlcykgJT4lCiAgbXV0YXRlKHRvdGFsX2NvbmNlbnRyYXRpb24gPSBzdW0oc3BlY2llc19wZXJfY3ViaWNfbWV0ZXIpLAogICAgICAgICBzcGVjaWVzX3BlcmNlbnRhZ2UgPSAoc3BlY2llc19wZXJfY3ViaWNfbWV0ZXIgLyB0b3RhbF9jb25jZW50cmF0aW9uKSAqIDEwMCkKCiMgQ3JlYXRlIHRoZSBzdGFja2VkIHBsb3QKY29uY2VudHJhdGlvbl9wZXJjZW50X3N0YWNrcGxvdCA8LSBnZ3Bsb3Qoc3BwX2NvbmNlbnRyYXRpb25fcGVyY2VudCwgYWVzKHggPSBYOC5kYXkuc2Vhc2NhcGVzLCB5ID0gc3BlY2llc19wZXJjZW50YWdlLCBmaWxsID0gc3BlY2llcykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWxfaGV4MikgKwogIGxhYnMoeCA9ICJTZWFzY2FwZSBjbGFzcyIsIHkgPSAiUmVsYXRpdmUgY29uY2VudHJhdGlvbiAoJSkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLCAgIyBTZXQgWC1heGlzIGxhYmVsIGZvbnQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpCmNvbmNlbnRyYXRpb25fcGVyY2VudF9zdGFja3Bsb3QKCiMgR2F0aGVyIGNvbHVtbnMgY29udGFpbmluZyBzcGVjaWVzIGNvdW50cyBpbnRvIGtleS12YWx1ZSBwYWlycyBhbmQgY2FsY3VsYXRlIGNvbmNlbnRyYXRpb25zCnNwcF9jb25jZW50cmF0aW9uX2xvbmcgPC0gc3BwX2RmICU+JQogIGdhdGhlcihrZXkgPSAic3BlY2llcyIsIHZhbHVlID0gImNvdW50IiwgLShYOC5kYXkuc2Vhc2NhcGVzOmRhdGUpKSAlPiUKICBtdXRhdGUoY29uY2VudHJhdGlvbiA9IChjb3VudCAvIHRvdGFsX3ZvbF9zYW1wbGVkKSAqIDFlNikKCiMgQ2FsY3VsYXRlIHRoZSBtZWFuIGNvbmNlbnRyYXRpb24gYW5kIGl0cyBzdGFuZGFyZCBkZXZpYXRpb24gcGVyIHNwZWNpZXMgYW5kIDhYLmRheS5zZWFzY2FwZXMgY2F0ZWdvcnkuIFRoaXMgaXMgbGlrZWx5IG1vcmUgcmVwcmVzZW50YXRpdmUgc2luY2UgdGhlIGFwcHJvYWNoIHdpbGwgY2FwdHVyZSBoaWdoIGNvbmNlbnRyYXRpb24gZXZlbnRzIChoaWdoIGNvdW50cyBpbiBsb3cgdm9sdW1lcykgdGhhdCBvdGhlcndpc2UgZ2V0IGZpbHRlcmVkIG91dCB3aGVuIHVzaW5nIGFuIG92ZXJhbGwgaW50ZWdyYXRlZCBzYW1wbGVkIHZvbHVtZSBhbmQgdG90YWwgY291bnRzIGZvciB0aGUgdG90YWwgY29uY2VudHJhdGlvbi4KYXZnX2NvbmNlbnRyYXRpb25fcGVyX2NsYXNzIDwtIHNwcF9jb25jZW50cmF0aW9uX2xvbmcgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcywgYFg4LmRheS5zZWFzY2FwZXNgKSAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuX2NvbmNlbnRyYXRpb24gPSBtZWFuKGNvbmNlbnRyYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBzZF9jb25jZW50cmF0aW9uID0gc2QoY29uY2VudHJhdGlvbiwgbmEucm0gPSBUUlVFKQogICkKCmF2Z19jb25jZW50cmF0aW9uX3Blcl9jbGFzcyRYOC5kYXkuc2Vhc2NhcGVzIDwtIGZhY3RvcihhdmdfY29uY2VudHJhdGlvbl9wZXJfY2xhc3MkWDguZGF5LnNlYXNjYXBlcywgbGV2ZWxzID0gYygiMyIsICI1IiwgIjciLCAiMTEiLCAiMTMiLCAiMTUiLCIyMSIsIjI3IikpCgphdmdfc3RhY2twbG90IDwtIGdncGxvdChhdmdfY29uY2VudHJhdGlvbl9wZXJfY2xhc3MsIGFlcyh4ID0gWDguZGF5LnNlYXNjYXBlcywgeSA9IG1lYW5fY29uY2VudHJhdGlvbiwgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAjIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWxfaGV4MikgKyAjIHVzZSBmb3Igem9vcGxhbmt0b24KICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsgIyB1c2UgZm9yIHBoeXRvcGxhbmt0b24KICBsYWJzKHggPSAiU2Vhc2NhcGUgY2xhc3MiLCB5ID0gIk1lYW4gZGVuc2l0eSAob3JnLiBtIl4iLTMifiIpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQphdmdfc3RhY2twbG90CgojIENhbGN1bGF0ZSBwZXJjZW50YWdlcwphdmdfY29uY2VudHJhdGlvbl9wZXJjZW50IDwtIGF2Z19jb25jZW50cmF0aW9uX3Blcl9jbGFzcyAlPiUKICBncm91cF9ieShgWDguZGF5LnNlYXNjYXBlc2ApICU+JQogIG11dGF0ZShtZWFuX2NvbmNlbnRyYXRpb25fcGVyY2VudCA9IG1lYW5fY29uY2VudHJhdGlvbiAvIHN1bShtZWFuX2NvbmNlbnRyYXRpb24pICogMTAwKQoKYXZnX3BlcmNlbnRfc3RhY2twbG90IDwtIGdncGxvdChhdmdfY29uY2VudHJhdGlvbl9wZXJjZW50LCBhZXMoeCA9IFg4LmRheS5zZWFzY2FwZXMsIHkgPSBtZWFuX2NvbmNlbnRyYXRpb25fcGVyY2VudCwgZmlsbCA9IHNwZWNpZXMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fcGFsX2hleDIpICsgIyB1c2UgZm9yIHpvb3BsYW5rdG9uCiAgIyBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsgIyB1c2UgZm9yIHBoeXRvcGxhbmt0b24KICBsYWJzKHggPSAiU2Vhc2NhcGUgY2xhc3MiLCB5ID0gIlJlbGF0aXZlIGNvbmNlbnRyYXRpb24gKCUpIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQphdmdfcGVyY2VudF9zdGFja3Bsb3QKCmBgYAoKCiMgR2VuZXJhdGUgcGxvdHMgCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShocmJydGhlbWVzKQpsaWJyYXJ5KHZpcmlkaXMpCgojICMgTG9hZCBzZWFzY2FwZSBjb2xvciBwYWxldHRlIHVzZWQgd2l0aCBNYXRsYWIgYW5kIGV4dHJhY3QgUkdCIHZhbHVlcyBmb3Igb2JzZXJ2ZWQgdW5pcXVlIHNlYXNjYXBlcwojIEZvciBOT0FBIG1hY2hpbmVzCiMgcGFsZXR0ZV9kaXIgPC0gIi9Vc2Vycy9lbnJpcXVlLm1vbnRlcy9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1lbnJpcXVlbW9udGVzMDFAZ21haWwuY29tL015IERyaXZlL0dEcml2ZS9zb2Z0d2FyZS9tYXRsYWIvbV9tYXAvc2Vhc2NhcGVfY20iCiMgRm9yIHBlcnNvbmFsIG1hY2hpbmUKcGFsZXR0ZV9kaXIgPC0gIn4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtZW5yaXF1ZW1vbnRlczAxQGdtYWlsLmNvbS9NeSBEcml2ZS9HRHJpdmUvc29mdHdhcmUvbWF0bGFiL21fbWFwL3NlYXNjYXBlX2NtIgpwYWxldHRlX2ZpbGUgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFsZXR0ZV9kaXIsIHBhdHRlcm4gPSAiY21hcDEuY3N2IiwgZnVsbC5uYW1lcyA9IFRSVUUpCnBhbGV0dGVfZGYgPC0gcmVhZC5jc3YocGFsZXR0ZV9maWxlLCBoZWFkZXIgPSBGQUxTRSkKY29sbmFtZXMocGFsZXR0ZV9kZikgPC0gYygiciIsICJnIiwgImIiKQp1bmlxdWVfc2Vhc2NhcGVzIDwtIHNvcnQodW5pcXVlKG5hLm9taXQoY3RkX21ldGEkWDguZGF5LnNlYXNjYXBlcykpKQpzdWJzZXRfcGFsZXR0ZV9kZiA8LSBwYWxldHRlX2RmW3VuaXF1ZV9zZWFzY2FwZXMsIF0KCiMgc2V0IFJHQiB2YWx1ZXMgZm9yIHRoZSBwbG90cwpyX3ZhbHMgPC0gcm91bmQoc3Vic2V0X3BhbGV0dGVfZGYkciAqIDI1NSwgMCkKZ192YWxzIDwtIHJvdW5kKHN1YnNldF9wYWxldHRlX2RmJGcgKiAyNTUsIDApCmJfdmFscyA8LSByb3VuZChzdWJzZXRfcGFsZXR0ZV9kZiRiICogMjU1LCAwKQpjdXN0b21fcGFsIDwtIGNiaW5kKHJfdmFscywgZ192YWxzLCBiX3ZhbHMpCmN1c3RvbV9wYWxfaGV4IDwtIHJnYihjdXN0b21fcGFsWywgMV0sIGN1c3RvbV9wYWxbLCAyXSwgY3VzdG9tX3BhbFssIDNdLCBtYXhDb2xvclZhbHVlPTI1NSkKIyBwYWxfZmluYWwgPC0gYyhjdXN0b21fcGFsX2hleFszXSwgY3VzdG9tX3BhbF9oZXhbNF0sIGN1c3RvbV9wYWxfaGV4WzVdLCApCgojIGZpbHRlciBvdXQgcm93cyB3aXRoIE5BIHZhbHVlcyBpbiBjb2x1bW4gc2Vhc2NhcGVzCmRmX2ZpbHRlcmVkIDwtIHRheGFfbWV0YVtjb21wbGV0ZS5jYXNlcyh0YXhhX21ldGEkWDguZGF5LnNlYXNjYXBlcyksXQoKIyBDb252ZXJ0IHRoZSAneCcgY29sdW1uIHRvIGNoYXJhY3RlcgpkZl9maWx0ZXJlZCRYOC5kYXkuc2Vhc2NhcGVzIDwtIGFzLmNoYXJhY3RlcihkZl9maWx0ZXJlZCRYOC5kYXkuc2Vhc2NhcGVzKQoKIyAjIFJlb3JkZXIgc2Vhc2NhcGUgY2F0ZWdvcmllcyBpbiBYIGF4aXMKZGZfZmlsdGVyZWQkWDguZGF5LnNlYXNjYXBlcyA8LSBmYWN0b3IoZGZfZmlsdGVyZWQkWDguZGF5LnNlYXNjYXBlcywgbGV2ZWxzID0gYygiMyIsICI1IiwgIjciLCAiMTEiLCAiMTMiLCAiMTUiLCIyMSIsIjI3IikpCgojIERlZmluZSBjdXN0b20gY29sb3JzIGZvciBlYWNoIGxldmVsCmN1c3RvbV9jb2xvcnMgPC0gYygiMyIgPSBjdXN0b21fcGFsX2hleFsxXSwgIjUiID0gY3VzdG9tX3BhbF9oZXhbMl0sICI3IiA9IGN1c3RvbV9wYWxfaGV4WzNdLAogICAgICAgICAgICAgICAgICAgIjExIiA9IGN1c3RvbV9wYWxfaGV4WzRdLCAiMTMiID0gY3VzdG9tX3BhbF9oZXhbNV0sICIxNSIgPSBjdXN0b21fcGFsX2hleFs2XSwKICAgICAgICAgICAgICAgICAgICIyMSIgPSBjdXN0b21fcGFsX2hleFs3XSwgIjI3IiA9IGN1c3RvbV9wYWxfaGV4WzhdKQoKIyBGaWx0ZXIgb3V0IHNlYXNjYXBlIGNsYXNzIGFzIGRlc2lyZWQKIyBkZl9maWx0ZXJlZCA8LSBkZl9maWx0ZXJlZFtkZl9maWx0ZXJlZCRYOC5kYXkuc2Vhc2NhcGVzICE9ICI1IiwgXQoKIyBQbG90CiMgU2VlIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy92aXJpZGlzL3ZpZ25ldHRlcy9pbnRyby10by12aXJpZGlzLmh0bWwgZm9yIGNvbG9yIHBhbGV0dGUgb3B0aW9ucwpwcCA8LSBkZl9maWx0ZXJlZCAlPiUKICBnZ3Bsb3QoIGFlcyh4PVg4LmRheS5zZWFzY2FwZXMsIHk9QXZnLmNobC5hLi51Zy5MLiwgZmlsbD1YOC5kYXkuc2Vhc2NhcGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgIyBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uPSJIIiwgZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjYpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9jb2xvcnMpICsKICAgIGdlb21faml0dGVyKGNvbG9yPSJncmV5Iiwgc2l6ZT0wLjgsIGFscGhhPTAuNCkgKwogICAgbGFicyh4ID0gIlNlYXNjYXBlIGNsYXNzIikgKwogICAgbGFicyh5ID0gZXhwcmVzc2lvbigiWyIqQ2hsLWEqIl0ifiBtdSoiZyJ+TF4tMSkpICsKICAgICMgbGFicyh5ID0gZXhwcmVzc2lvbigiU2FsaW5pdHkiKSkgKwogICAgIyBsYWJzKHkgPSBleHByZXNzaW9uKHBhc3RlKCJUZW1wZXJhdHVyZSAoIiwgZGVncmVlLCAiQykgYXQgMSBtIGRlcHRoIikpKSArCiAgICAjIGxhYnMoeSA9IGV4cHJlc3Npb24oIlsiKkRPKiJdIn5tZ35MXi0xKSkgKwogICAgIyBsYWJzKHkgPSBleHByZXNzaW9uKCJbIipOT1sieCJdKiJdIiB+IG11KiJNIikpICsKICAgICMgbGFicyh5ID0gZXhwcmVzc2lvbigiWyIqUE9bNF1eIjMtIioiXSIgfiBtdSoiTSIpKSArCiAgICAjIGxhYnMoeSA9IGV4cHJlc3Npb24oIlsiKk5IWzRdXiIrIioiXSIgfiBtdSoiTSIpKSArCiAgICAjIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpKQogICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gYygiVHJvcGljYWwvU3VidHJvcGljYWwgVXB3ZWxsaW5nIiwgCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJvcGljYWwgU2VhcyIsIAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIldhcm0sIEJsb29tcywgSGlnaCBOdXRzIiwgCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJvcGljYWwvU3VidHJvcGljYWwgVHJhbnNpdGlvbiIsIAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIlRlbXBlcmF0ZSBUcmFuc2l0aW9uIikpICsKICAgIHRoZW1lX2lwc3VtKCkgKwogICAgdGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkKICAgICkgKwogICAgIyBnZ3RpdGxlKCJBIGJveHBsb3Qgd2l0aCBqaXR0ZXIiKSArCiAgICAjIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArCiAgeWxpbSgwLCA3KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBmYW1pbHkgPSAiQXJpYWwiKSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiwgZmFtaWx5ID0gIkFyaWFsIikpICsKICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGhqdXN0ID0gMC41LCBmYW1pbHkgPSAiQXJpYWwiKSwKICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGhqdXN0ID0gMC41LCBmYW1pbHkgPSAiQXJpYWwiKSkgKwogICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSkgCnBwCmBgYAoKIyBDcmVhdGUgc3RhY2twbG90cyBzaG93aW5nIHJlbGF0aXZlIGZyZXF1ZW5jeSB1c2luZyBjb3VudHMgb25seSBvZiBwbGFua3RvbiB0YXhhIHBlciBzZWFzY2FwZSBjYXRlZ29yeQpgYGB7cn0KIyBjb252ZXJ0IGFidW5kYW5jZSBjb2x1bW5zIHRvIHJlbGF0aXZlIGZyZXF1ZW5jeQoKIyBzdWJzZXRzIHRheGEgZm9yIHpvb3BsYW5rdG9uCiMgZGZfc3Vic2V0IDwtIGRmX2ZpbHRlcmVkWyAsIGMoIlg4LmRheS5zZWFzY2FwZXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY2FudGhhcmVhIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29wZXBvZHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFY2hpbm9kZXJtcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkplbGxpZXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMYXJ2YWNlYW5zIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9seWNoYWV0ZXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGFldG9nbmF0aHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQdGVyb3BvZHMiKV0KCiMgc3Vic2V0cyB0YXhhIGZvciBwaHl0b3BsYW5rdG9uCmRmX3N1YnNldCA8LSBkZl9maWx0ZXJlZFsgLCBjKCJYOC5kYXkuc2Vhc2NhcGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDZXJhdGl1bSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhZXRvY2Vyb3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYWluMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhaW4zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHdWluYXJkaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5lb2NhbHlwdHJlbGxhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUcmljaG8iKV0KCiMgc3Vic2V0cyB0YXhhIGZvciBhbGwgc3BlY2llcwojIGRmX3N1YnNldCA8LSBkZl9maWx0ZXJlZFsgLCBjKCJYOC5kYXkuc2Vhc2NhcGVzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNlcmF0aXVtIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYWV0b2Nlcm9zIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpYXRvbXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlhdG9tczIiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR3VpbmFyZGlhIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5lb2NhbHlwdHJlbGxhIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRyaWNob2Rlc21pdW0iLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWNhbnRoYXJlYSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3BlcG9kcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFY2hpbm9kZXJtcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJKZWxsaWVzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhcnZhY2VhbnMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9seWNoYWV0ZXMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhZXRvZ25hdGhzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlB0ZXJvcG9kcyIpXQoKIyByZXNoYXBlIHRoZSBkYXRhIHRvIGxvbmcgZm9ybWF0IApkZl9sb25nIDwtIHRpZHlyOjpnYXRoZXIoZGZfc3Vic2V0LCBrZXkgPSAiU3BlY2llcyIsIHZhbHVlID0gIkZyZXF1ZW5jeSIsIC1YOC5kYXkuc2Vhc2NhcGVzKQoKIyBjYWxjdWxhdGUgcmVsYXRpdmUgZnJlcXVlbmNpZXMKZGZfc3VtIDwtIGRmX2xvbmcgJT4lCiAgZ3JvdXBfYnkoWDguZGF5LnNlYXNjYXBlcywgU3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKG4gPSBzdW0oRnJlcXVlbmN5KSkgJT4lCiAgbXV0YXRlKGZyZXEgPSBuIC8gc3VtKG4pKQoKIyBTZWFzY2FwZSBjbGFzcyBuYW1lczoKIyAiQ2xhc3MgMTEiIC0gVHJvcGljYWwvU3VidHJvcGljYWwgVXB3ZWxsaW5nCiMgIkNsYXNzIDE1IiAtIFRyb3BpY2FsIFNlYXMKIyAiQ2xhc3MgMjEiIC0gV2FybSwgQmxvb21zLCBIaWdoIE51dHMKIyAiQ2xhc3MgMyIgLSBUcm9waWNhbC9TdWJ0cm9waWNhbCBUcmFuc2l0aW9uCiMgIkNsYXNzIDciIC0gVGVtcGVyYXRlIFRyYW5zaXRpb24KCiMgIyBTZWxlY3QgZGVzaXJlZCBzZWFzY2FwZXMgYW5kIHJlb3JkZXIgY2F0ZWdvcmllcyBpbiBYIGF4aXMKZGZfc3VtJFg4LmRheS5zZWFzY2FwZXMgPC0gZmFjdG9yKGRmX3N1bSRYOC5kYXkuc2Vhc2NhcGVzLCBsZXZlbHMgPSBjKCIzIiwgIjUiLCAiNyIsICIxMSIsICIxMyIsICIxNSIsIjIxIiwiMjciKSkKCiMgRmlsdGVyIG91dCBzZWFzY2FwZSBjbGFzcyBhcyBkZXNpcmVkCmV4Y2x1ZGVfY2xhc3NlcyA8LSBjKDUsIDcsIDExKQpkZl9zdW0gPC0gZGZfc3VtWyFkZl9zdW0kWDguZGF5LnNlYXNjYXBlcyAlaW4lIGV4Y2x1ZGVfY2xhc3NlcywgXQoKIyBVc2UgcXVhbGl0YXRpdmUgcGFsZXR0ZXM6IGh0dHBzOi8vY29sb3JicmV3ZXIyLm9yZy8jdHlwZT1xdWFsaXRhdGl2ZSZzY2hlbWU9QWNjZW50Jm49NwpjdXN0b21fcGFsX2hleDIgPC0gYygnI2U0MWExYycsJyMzNzdlYjgnLCcjNGRhZjRhJywnIzk4NGVhMycsJyNmZjdmMDAnLCcjZmZmZjMzJywnI2E2NTYyOCcsJyNmNzgxYmYnKQojIGN1c3RvbV9wYWxfaGV4MiA8LSBjKCcjMWI5ZTc3JywnI2Q5NWYwMicsJyM3NTcwYjMnLCcjZTcyOThhJywnIzY2YTYxZScsJyNlNmFiMDInLCcjYTY3NjFkJykKCiMgY3JlYXRlIHRoZSBzdGFja3Bsb3QKcXEgPC0gZ2dwbG90KGRmX3N1bSwgYWVzKHggPSBYOC5kYXkuc2Vhc2NhcGVzLCB5ID0gZnJlcSwgZmlsbCA9IFNwZWNpZXMpKSArCiAgIyBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uPSJTZXQzIiwgZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjgpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjgpICsKICAjIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9wYWxfaGV4MikgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIlNlYXNjYXBlIGNsYXNzIikgKwogIGxhYnMoeSA9ICJSZWxhdGl2ZSBmcmVxdWVuY3kiKSArCiAgIyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz0gYygiVHJvcGljYWwvU3VidHJvcGljYWwgVXB3ZWxsaW5nIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJvcGljYWwgU2VhcyIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldhcm0sIEJsb29tcywgSGlnaCBOdXRzIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJvcGljYWwvU3VidHJvcGljYWwgVHJhbnNpdGlvbiIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRlbXBlcmF0ZSBUcmFuc2l0aW9uIikpICsKICAjIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLCAgIyBTZXQgWC1heGlzIGxhYmVsIGZvbnQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpIAogICN0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpKQpxcQpgYGAKCgojIENvbXB1dGUgU2hhbm5vbiBJbmRleApgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeSh2ZWdhbikKCiMgU2VsZWN0IHNwZWNpZXMgZm9yIFNoYW5ub24gY2FsY3VsYXRpb24KZGZfc3Vic2V0X3NoYW5ub24gPC0gZGZfZmlsdGVyZWRbICwgYygiWDguZGF5LnNlYXNjYXBlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY2FudGhhcmVhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvcGVwb2RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVjaGlub2Rlcm1zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkplbGxpZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGFydmFjZWFucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb2x5Y2hhZXRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYWV0b2duYXRocyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQdGVyb3BvZHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2VyYXRpdW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhZXRvY2Vyb3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2hhaW4yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNoYWluMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHdWluYXJkaWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmVvY2FseXB0cmVsbGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVHJpY2hvIildCgojIHJlc2hhcGUgdGhlIGRhdGEgdG8gbG9uZyBmb3JtYXQKZGZfbG9uZyA8LSB0aWR5cjo6Z2F0aGVyKGRmX3N1YnNldF9zaGFubm9uLCBrZXkgPSAiU3BlY2llcyIsIHZhbHVlID0gIkFidW5kYW5jZSIsIC1YOC5kYXkuc2Vhc2NhcGVzKQoKIyBFeGNsdWRlIHNlYXNjYXBlcwpleGNsdWRlX3NlYXNjYXBlcyA8LSBjKDUsIDcsIDExKQoKIyBDb21wdXRlIFNoYW5ub24gZGl2ZXJzaXR5IHBlciBzZWFzY2FwZSBjbGFzcwpzaGFubm9uX2RmIDwtIGRmX2xvbmcgJT4lIAogIGdyb3VwX2J5KFg4LmRheS5zZWFzY2FwZXMpICU+JSAKICBzdW1tYXJpc2Uoc2hhbm5vbiA9IGRpdmVyc2l0eShBYnVuZGFuY2UsIGluZGV4ID0gInNoYW5ub24iKSkKCiMgRmlsdGVyIHRoZSBkYXRhIHRvIGV4Y2x1ZGUgc3BlY2lmaWVkIHNlYXNjYXBlcwpzaGFubm9uX2RmX2ZpbHRlcmVkIDwtIHNoYW5ub25fZGZbIXNoYW5ub25fZGYkWDguZGF5LnNlYXNjYXBlcyAlaW4lIGV4Y2x1ZGVfc2Vhc2NhcGVzLCBdCgojIGNyZWF0ZSB0aGUgYmFyIHBsb3Qgb2YgU2hhbm5vbiBkaXZlcnNpdHkKZmYgPC0gZ2dwbG90KHNoYW5ub25fZGZfZmlsdGVyZWQsIGFlcyh4ID0gWDguZGF5LnNlYXNjYXBlcywgeSA9IHNoYW5ub24sIGZpbGwgPSBYOC5kYXkuc2Vhc2NhcGVzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgIyBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uPSJwbGFzbWEiLCBkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuNikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9jb2xvcnMpICsKICB4bGFiKCJTZWFzY2FwZSBDbGFzcyIpICsKICB5bGFiKCJTaGFubm9uIERpdmVyc2l0eSIpICsKICAjIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPSBjKCJUcm9waWNhbC9TdWJ0cm9waWNhbCBVcHdlbGxpbmciLCAKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUcm9waWNhbCBTZWFzIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2FybSwgQmxvb21zLCBIaWdoIE51dHMiLCAKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUcm9waWNhbC9TdWJ0cm9waWNhbCBUcmFuc2l0aW9uIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVtcGVyYXRlIFRyYW5zaXRpb24iKSkgKwogICMgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLCAgIyBTZXQgWC1heGlzIGxhYmVsIGZvbnQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSkgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICBndWlkZXMoKQpmZgoKIyAjIFN1YnNldCB0aGUgZGF0YSB0byBleGNsdWRlIHNwZWNpZmllZCBzZWFzY2FwZXMKZmlsdGVyZWRfdGF4YV9tZXRhIDwtIHRheGFfbWV0YVtjb21wbGV0ZS5jYXNlcyh0YXhhX21ldGEkWDguZGF5LnNlYXNjYXBlcyksIF0KZmlsdGVyZWRfdGF4YV9tZXRhIDwtIGZpbHRlcmVkX3RheGFfbWV0YVshZmlsdGVyZWRfdGF4YV9tZXRhJFg4LmRheS5zZWFzY2FwZXMgJWluJSBleGNsdWRlX3NlYXNjYXBlcywgXQoKIyAjIFBsb3Qgc2FtcGxlZCBzZWFzY2FwZSBmcmVxdWVuY3kKdHQgPC0gZ2dwbG90KGZpbHRlcmVkX3RheGFfbWV0YSwgYWVzKHggPSBmYWN0b3IoWDguZGF5LnNlYXNjYXBlcyksIGZpbGwgPSBmYWN0b3IoWDguZGF5LnNlYXNjYXBlcykpKSArCiAgZ2VvbV9iYXIoY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9jb2xvcnMpICsKICBsYWJzKHggPSAiU2Vhc2NhcGUgQ2xhc3MiLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyKSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMikpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkKdHQKCiMgIyBDb3VudHMgb2Ygc3BlY2llcyBwZXIgc2Vhc2NhcGUKZGZfc3VtX2FidW5kIDwtIGRmX2xvbmcgJT4lCiAgZ3JvdXBfYnkoWDguZGF5LnNlYXNjYXBlcywgU3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKG4gPSBzdW0oQWJ1bmRhbmNlKSkgCgpkZl9zdW1fYWJ1bmRfZmlsdCA8LSBkZl9zdW1fYWJ1bmRbZGZfc3VtX2FidW5kJFNwZWNpZXMgPT0gIlB0ZXJvcG9kcyIsXQojIEZpbHRlciB0aGUgZGF0YSB0byBleGNsdWRlIHNwZWNpZmllZCBzZWFzY2FwZXMKZGZfc3VtX2FidW5kX2ZpbHQyIDwtIGRmX3N1bV9hYnVuZF9maWx0WyFkZl9zdW1fYWJ1bmRfZmlsdCRYOC5kYXkuc2Vhc2NhcGVzICVpbiUgZXhjbHVkZV9zZWFzY2FwZXMsIF0KCmRkIDwtIGdncGxvdChkZl9zdW1fYWJ1bmRfZmlsdDIsIGFlcyh4ID0gZmFjdG9yKFg4LmRheS5zZWFzY2FwZXMpLCB5ID0gbiwgZmlsbCA9IGZhY3RvcihYOC5kYXkuc2Vhc2NhcGVzKSkpICsKICBnZW9tX2Jhcihjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43LCBzdGF0ID0gImlkZW50aXR5IikgKwogICMgc2NhbGVfZmlsbF92aXJpZGlzKG9wdGlvbiA9ICJtYWdtYSIsIGRpc2NyZXRlID0gVFJVRSwgYWxwaGEgPSAwLjgpCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX2NvbG9ycykgKwogIHRoZW1lX21pbmltYWwoKSAKZGQKCiMgQ29tcHV0ZSBjb3VudHMgb2Ygc2VsZWN0ZWQgc3BlY2llcyBwZXIgc2Vhc2NhcGUgY2xhc3Mgbm9ybWFsaXplZCBieSBmcmVxdWVuY3kgb2Ygc2Vhc2NhcGVzCiMgcmVzaGFwZSB0aGUgZGF0YSB0byBsb25nIGZvcm1hdApkZl9sb25nMiA8LSB0aWR5cjo6Z2F0aGVyKGRmX3N1YnNldF9zaGFubm9uLCBrZXkgPSAiU3BlY2llcyIsIHZhbHVlID0gIkFidW5kYW5jZSIsIC1YOC5kYXkuc2Vhc2NhcGVzKQoKc3BwX3NlYXNjYXBlX25vcm1hbGl6ZWQgPC0gZGZfbG9uZzIgJT4lCiAgZmlsdGVyKFNwZWNpZXMgPT0gIlB0ZXJvcG9kcyIpICU+JQogIGdyb3VwX2J5KFg4LmRheS5zZWFzY2FwZXMpICU+JQogIHN1bW1hcmlzZShzcHBfY291bnQgPSBzdW0oQWJ1bmRhbmNlKSkKCiMgQ29tcHV0ZSBmcmVxdWVuY2llcyBvZiBlYWNoIHNlYXNjYXBlIGNsYXNzCnNlYXNjYXBlX2ZyZXF1ZW5jaWVzIDwtIGRmX2xvbmcyICU+JQogIGNvdW50KFg4LmRheS5zZWFzY2FwZXMpICU+JQogIHJlbmFtZShmcmVxID0gbikKCiMgTWVyZ2UgY291bnRzIHdpdGggZnJlcXVlbmNpZXMKc3BwX3NlYXNjYXBlX25vcm1hbGl6ZWQgPC0gbWVyZ2Uoc3BwX3NlYXNjYXBlX25vcm1hbGl6ZWQsIHNlYXNjYXBlX2ZyZXF1ZW5jaWVzLCBieSA9ICJYOC5kYXkuc2Vhc2NhcGVzIikKCiMgTm9ybWFsaXplIGNvdW50cyBieSBmcmVxdWVuY3kKc3BwX3NlYXNjYXBlX25vcm1hbGl6ZWQkc3BwX25vcm1hbGl6ZWQgPC0gKHNwcF9zZWFzY2FwZV9ub3JtYWxpemVkJHNwcF9jb3VudCAvIHNwcF9zZWFzY2FwZV9ub3JtYWxpemVkJGZyZXEpICogMTAwMApzcHBfc2Vhc2NhcGVfbm9ybWFsaXplZF9maWx0IDwtIHNwcF9zZWFzY2FwZV9ub3JtYWxpemVkWyFzcHBfc2Vhc2NhcGVfbm9ybWFsaXplZCRYOC5kYXkuc2Vhc2NhcGVzICVpbiUgZXhjbHVkZV9zZWFzY2FwZXMsIF0KCmJiIDwtIGdncGxvdChzcHBfc2Vhc2NhcGVfbm9ybWFsaXplZF9maWx0LCBhZXMoeCA9IGZhY3RvcihYOC5kYXkuc2Vhc2NhcGVzKSwgeSA9IHNwcF9ub3JtYWxpemVkLCBmaWxsID0gZmFjdG9yKFg4LmRheS5zZWFzY2FwZXMpKSkgKwogIGdlb21fYmFyKGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjcsIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX2NvbG9ycykgKwogIGxhYnMoeCA9ICJTZWFzY2FwZSBDbGFzcyIsIHkgPSAiQ291bnRzIC8gU2Vhc2NhcGUgZnJlcSAqIDEwMDAiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAjICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAjICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICAjIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpLAogICMgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICAjIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICBndWlkZXMoKQpiYgoKYGBgCgojIFBDIHBsb3QKYGBge3J9CmxpYnJhcnkoZ2dhbHQpCgojIFBlcmZvcm0gcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyBvbiB0aGUgY291bnQgZGF0YQoKIyBmb3IgaHlkcm9ncmFwaHkKc2VsX3ZhcnMgPC0gYygKICAiWDguZGF5LnNlYXNjYXBlcyIsCiAgInNhbGluaXR5IiwKICAiQXZnLmNobC5hLi51Zy5MLiIsCiAgIlBPNC4uLnVNLiIsCiAgIk5PMy5OTzIuLnVNLiIsCiAgIk5INC4uLnVNLiIsCiAgInRlbXAuLmRlZ0MuIikKCiMgZm9yIHRheG9ub215CiMgc2VsX3ZhcnMgPC0gYygiWDguZGF5LnNlYXNjYXBlcyIsCiMgICAgICAgICAgICAgICAiQWNhbnRoYXJlYSIsCiMgICAgICAgICAgICAgICAiQ29wZXBvZHMiLAojICAgICAgICAgICAgICAgIkVjaGlub2Rlcm1zIiwKIyAgICAgICAgICAgICAgICJKZWxsaWVzIiwKIyAgICAgICAgICAgICAgICJMYXJ2YWNlYW5zIiwKIyAgICAgICAgICAgICAgICJQb2x5Y2hhZXRzIiwKIyAgICAgICAgICAgICAgICJDaGFldG9nbmF0aHMiLAojICAgICAgICAgICAgICAgIlB0ZXJvcG9kcyIpCgojIHNlbF92YXJzIDwtIGMoIlg4LmRheS5zZWFzY2FwZXMiLAojICAgICAgICAgICAgICAgIkNlcmF0aXVtIiwKIyAgICAgICAgICAgICAgICJDaGFldG9jZXJvcyIsCiMgICAgICAgICAgICAgICAiQ2hhaW4yIiwKIyAgICAgICAgICAgICAgICJDaGFpbjMiLAojICAgICAgICAgICAgICAgIkd1aW5hcmRpYSIsCiMgICAgICAgICAgICAgICAiTmVvY2FseXB0cmVsbGEiLAojICAgICAgICAgICAgICAgIlRyaWNobyIpCgojIHNlbF92YXJzIDwtIGMoIlg4LmRheS5zZWFzY2FwZXMiLAojICAgICAgICAgICAgICAgIkFjYW50aGFyZWEiLAojICAgICAgICAgICAgICAgIkNvcGVwb2RzIiwKIyAgICAgICAgICAgICAgICJFY2hpbm9kZXJtcyIsCiMgICAgICAgICAgICAgICAiSmVsbGllcyIsCiMgICAgICAgICAgICAgICAiTGFydmFjZWFucyIsCiMgICAgICAgICAgICAgICAiUG9seWNoYWV0cyIsCiMgICAgICAgICAgICAgICAiQ2hhZXRvZ25hdGhzIiwKIyAgICAgICAgICAgICAgICJQdGVyb3BvZHMiLAojICAgICAgICAgICAgICAgIkNlcmF0aXVtIiwKIyAgICAgICAgICAgICAgICJDaGFldG9jZXJvcyIsCiMgICAgICAgICAgICAgICAiQ2hhaW4yIiwKIyAgICAgICAgICAgICAgICJDaGFpbjMiLAojICAgICAgICAgICAgICAgIkd1aW5hcmRpYSIsCiMgICAgICAgICAgICAgICAiTmVvY2FseXB0cmVsbGEiLAojICAgICAgICAgICAgICAgIlRyaWNobyIpCgojIGZpbHRlciBvdXQgcm93cyB3aXRoIE5BIHZhbHVlcyBpbiBjb2x1bW4gc2Vhc2NhcGVzCiMgZGZfZmlsdGVyZWRfcGNhIDwtIHRheGFfbWV0YVtjb21wbGV0ZS5jYXNlcyh0YXhhX21ldGEkWDguZGF5LnNlYXNjYXBlcyksIF0KZGZfZmlsdGVyZWRfcGNhIDwtIHRheGFfbWV0YVtjb21wbGV0ZS5jYXNlcyh0YXhhX21ldGFbLCBzZWxfdmFyc10pLCBdCiMgZXhjbHVkZV9zZWFzY2FwZXMgPC0gYyg1LCA3LCAxMSkKZXhjbHVkZV9zZWFzY2FwZXMgPC0gMApmaWx0X2RmX3BjYSA8LSBkZl9maWx0ZXJlZF9wY2FbIWRmX2ZpbHRlcmVkX3BjYSRYOC5kYXkuc2Vhc2NhcGVzICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZV9zZWFzY2FwZXMsIHNlbF92YXJzXQoKIyBTZWxlY3QgbnVtZXJpYyBjb2x1bW5zIGluIGZpbHRfZGZfcGNhCm51bWVyaWNfY29scyA8LSBzYXBwbHkoZmlsdF9kZl9wY2EsIGlzLm51bWVyaWMpCiMgSWRlbnRpZnkgbnVtZXJpYyBjb2x1bW5zIGV4Y2VwdCB0aGUgZmlyc3Qgb25lCm51bWVyaWNfY29scyA8LSAyOm5jb2woZmlsdF9kZl9wY2EpCgojIFRyYW5zZm9ybSBudW1lcmljIGNvbHVtbnMgdG8gbG9nIHNjYWxlCmZpbHRfZGZfcGNhW251bWVyaWNfY29sc10gPC0gbGFwcGx5KGZpbHRfZGZfcGNhW251bWVyaWNfY29sc10sIGZ1bmN0aW9uKHgpIGxvZyh4ICsgMSkpCgoKIyBwY2EgPC0gcHJjb21wKGZpbHRfZGZfcGNhWywgYygic2FsaW5pdHkiLCAiQXZnLmNobC5hLi51Zy5MLiIsICJQTzQuLi51TS4iLCAiTk8zLk5PMi4udU0uIildLCBzY2FsZS4gPSBUUlVFKQpwY2EgPC0gcHJjb21wKGZpbHRfZGZfcGNhWywgLTFdLCBzY2FsZS4gPSBUUlVFKQoKIyBFeHRyYWN0IFBDMSBhbmQgUEMyIHNjb3JlcyBmb3IgZWFjaCBzYW1wbGluZyBldmVudAojIHBjX3Njb3JlcyA8LSBkYXRhLmZyYW1lKHNlYXNjYXBlID0gZGZfc3Vic2V0JFg4LmRheS5zZWFzY2FwZXMsICMgZm9yIHRheG9ub21pYyBhbmFseXNpcyAKcGNfc2NvcmVzIDwtIGRhdGEuZnJhbWUoc2Vhc2NhcGUgPSBhcy5jaGFyYWN0ZXIoZmlsdF9kZl9wY2EkWDguZGF5LnNlYXNjYXBlcyksICMgZm9yIGh5ZHJvZ3JhcGh5CiAgICAgICAgICAgICAgICAgICAgICAgIFBDMSA9IHBjYSR4WywgMV0sIAogICAgICAgICAgICAgICAgICAgICAgICBQQzIgPSBwY2EkeFssIDJdKQoKIyBDcmVhdGUgdGhlIHBsb3QKcGNfc2NvcmVzJHNlYXNjYXBlIDwtIGZhY3RvcihwY19zY29yZXMkc2Vhc2NhcGUsIGxldmVscyA9IGMoIjMiLCAiNSIsICI3IiwgIjExIiwgIjEzIiwgIjE1IiwgIjIxIiwgIjI3IikpCmJiIDwtIGdncGxvdChwY19zY29yZXMsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IHNlYXNjYXBlKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGxhYnMoeCA9ICJQQzEiLCB5ID0gIlBDMiIsIGNvbG9yID0gIlNlYXNjYXBlIikgCgojIGFkZCBjaXJjbGUgYXJvdW5kIGNsdXN0ZXIgb2YgZGF0YSBwb2ludHMKIyBjdXN0b21fY29sb3JzX3BjYSA8LSBjdXN0b21fcGFsX2hleFtjKDEsIDUsIDYsIDcsIDgpXQpjdXN0b21fY29sb3JzX3BjYSA8LSBjdXN0b21fY29sb3JzCgp5eSA8LSBnZ3Bsb3QocGNfc2NvcmVzLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBzZWFzY2FwZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X2VsbGlwc2UoYWVzKGZpbGwgPSBzZWFzY2FwZSksIGxldmVsID0gMC45MCwgZ2VvbSA9ICJwb2x5Z29uIiwgYWxwaGEgPSAwLjMsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fY29sb3JzX3BjYSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9jb2xvcnNfcGNhKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB4bGltKC0yLDIpICsKICB5bGltKC0yLDIpICsKICAjIHhsaW0oLTEsMSkgKwogICMgeWxpbSgtMSwxKSArCiAgZ2VvbV9wb2ludChzaXplPTIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0yKSkpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMikpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKQoKeXkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojICMgQ3JlYXRlIFBDQSB3aXRoIGVpZ2VudmVjdG9ycwojIEV4dHJhY3QgcHJpbmNpcGFsIGNvbXBvbmVudCBzY29yZXMKcGNfc2NvcmVzMiA8LSBwY2EkeAojIEV4dHJhY3QgZWlnZW52ZWN0b3JzCmVpZ2VudmVjdG9ycyA8LSBwY2Ekcm90YXRpb24KIyBDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudAp0b3RhbF92YXJpYW5jZSA8LSBzdW0ocGNhJHNkZXZeMikKcGNfdmFyX3BlcmNlbnQgPC0gcm91bmQoMTAwICogKHBjYSRzZGV2XjIpIC8gdG90YWxfdmFyaWFuY2UsIDEpCgojIENvbnZlcnQgWDguZGF5LnNlYXNjYXBlcyB0byBhIGZhY3RvcgpmaWx0X2RmX3BjYSRYOC5kYXkuc2Vhc2NhcGVzIDwtIGFzLmZhY3RvcihmaWx0X2RmX3BjYSRYOC5kYXkuc2Vhc2NhcGVzKQoKIyAjIEZvciBoeWRyb2dyYXBoeQpxcSA8LSBnZ3Bsb3QoZmlsdF9kZl9wY2EsIGFlcyh4ID0gcGNfc2NvcmVzMlssMV0sIHkgPSBwY19zY29yZXMyWywyXSwgY29sb3IgPSBYOC5kYXkuc2Vhc2NhcGVzKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGN1c3RvbV9jb2xvcnNfcGNhKSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBlaWdlbnZlY3RvcnNbMSwgMV0sIHllbmQgPSBlaWdlbnZlY3RvcnNbMiwgMV0pLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkIHZlY3RvciBmb3IgUEMxCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBlaWdlbnZlY3RvcnNbMSwgMl0sIHllbmQgPSBlaWdlbnZlY3RvcnNbMiwgMl0pLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzIKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCAzXSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCAzXSksCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSksIGNvbG9yID0gImJsYWNrIikgKyAjIEFkZCB2ZWN0b3IgZm9yIFBDMwogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDRdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDRdKSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMSwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM0CiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBlaWdlbnZlY3RvcnNbMSwgNV0sIHllbmQgPSBlaWdlbnZlY3RvcnNbMiwgNV0pLAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzUKICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA2XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA2XSksCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSksIGNvbG9yID0gImJsYWNrIikgKyAjIEFkZCB2ZWN0b3IgZm9yIFBDNgogIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCAxXSwgeSA9IGVpZ2VudmVjdG9yc1syLCAxXSwgCiAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzEgKCIsIHBjX3Zhcl9wZXJjZW50WzFdLCAiJTogU2FsaW5pdHkpIiwgc2VwID0gIiIpKSwKICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEMxCiAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDJdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDJdLCAKICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIlBDMiAoIiwgcGNfdmFyX3BlcmNlbnRbMl0sICIlOiBDaGxhKSIsIHNlcCA9ICIiKSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDMgogIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCAzXSwgeSA9IGVpZ2VudmVjdG9yc1syLCAzXSwgCiAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzMgKCIsIHBjX3Zhcl9wZXJjZW50WzNdLCAiJTogUGhvc3BoYXRlKSIsIHNlcCA9ICIiKSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDMwogIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCA0XSwgeSA9IGVpZ2VudmVjdG9yc1syLCA0XSwgCiAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzQgKCIsIHBjX3Zhcl9wZXJjZW50WzRdLCAiJTogTk94KSIsIHNlcCA9ICIiKSksCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDNAogIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCA1XSwgeSA9IGVpZ2VudmVjdG9yc1syLCA1XSwgCiAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzUgKCIsIHBjX3Zhcl9wZXJjZW50WzVdLCAiJTogQW1tb25pdW0pIiwgc2VwID0gIiIpKSwKICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM1CiAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDZdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDZdLCAKICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIlBDNiAoIiwgcGNfdmFyX3BlcmNlbnRbNl0sICIlOiBUZW1wZXJhdHVyZSkiLCBzZXAgPSAiIikpLAogICAgICAgICAgICB2anVzdCA9IC0wLjUsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkIGxhYmVsIGZvciBQQzYKICBsYWJzKHggPSAiUEMxIiwgeSA9ICJQQzIiLCBjb2xvciA9ICJTZWFzY2FwZSBjbGFzcyIpICsKICB4bGltKC0xLjUsIDEuNSkgKwogIHlsaW0oLTEuNSwgMS41KSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NSkpKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwgICMgU2V0IFgtYXhpcyBsYWJlbCBmb250IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpCnFxCgoKIyAjICMgRm9yIHBoeXRvcGxhbmt0b24KIyBxcTIgPC0gZ2dwbG90KGZpbHRfZGZfcGNhLCBhZXMoeCA9IHBjX3Njb3JlczJbLDFdLCB5ID0gcGNfc2NvcmVzMlssM10sIGNvbG9yID0gWDguZGF5LnNlYXNjYXBlcykpICsKIyAgIGdlb21fcG9pbnQoc2l6ZSA9IDQpICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjdXN0b21fY29sb3JzX3BjYSkgKwojICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBlaWdlbnZlY3RvcnNbMSwgMV0sIHllbmQgPSBlaWdlbnZlY3RvcnNbMiwgMV0pLAojICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSksIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgdmVjdG9yIGZvciBQQzEKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDJdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDJdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzIKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDNdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDNdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzMKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDRdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDRdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzQKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDVdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDVdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzUKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDZdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDZdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzYKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDddLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDddKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgdmVjdG9yIGZvciBQQzcKIyAgIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCAxXSwgeSA9IGVpZ2VudmVjdG9yc1syLCAxXSwgCiMgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIlBDMSAoIiwgcGNfdmFyX3BlcmNlbnRbMV0sICIlOiBDZXJhdGl1bSkiLCBzZXAgPSAiIikpLAojICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDMQojICAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDJdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDJdLCAKIyAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZSgiUEMyICgiLCBwY192YXJfcGVyY2VudFsyXSwgIiU6IENoYWV0b2Nlcm9zKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEMyCiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgM10sIHkgPSBlaWdlbnZlY3RvcnNbMiwgM10sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzMgKCIsIHBjX3Zhcl9wZXJjZW50WzNdLCAiJTogRGlhdG9tcykiLCBzZXAgPSAiIikpLAojICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDMwojICAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDRdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDRdLCAKIyAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZSgiUEM0ICgiLCBwY192YXJfcGVyY2VudFs0XSwgIiU6IERpYXRvbXMyKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM0CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgNV0sIHkgPSBlaWdlbnZlY3RvcnNbMiwgNV0sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzUgKCIsIHBjX3Zhcl9wZXJjZW50WzVdLCAiJTogR3VpbmFyZGlhKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM1CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgNl0sIHkgPSBlaWdlbnZlY3RvcnNbMiwgNl0sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzYgKCIsIHBjX3Zhcl9wZXJjZW50WzZdLCAiJTogTmVvY2FseXB0cmVsbGEpIiwgc2VwID0gIiIpKSwKIyAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkIGxhYmVsIGZvciBQQzYKIyAgIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCA3XSwgeSA9IGVpZ2VudmVjdG9yc1syLCA3XSwgCiMgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIlBDNyAoIiwgcGNfdmFyX3BlcmNlbnRbN10sICIlOiBUcmljaG9kZXNtaXVtKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM3CiMgICBsYWJzKHggPSAiUEMxIiwgeSA9ICJQQzMiLCBjb2xvciA9ICJYOC5kYXkuc2Vhc2NhcGVzIikgKwojICAgeGxpbSgtMSwgMSkgKwojICAgeWxpbSgtMSwgMSkgKwojICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MikpKSArIAojICAgdGhlbWVfY2xhc3NpYygpICsKIyAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksICAjIFNldCBYLWF4aXMgbGFiZWwgZm9udCBzaXplCiMgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSArCiMgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwKIyAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSArCiMgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSAKIyBxcTIKIyAKIyAKIyAjICMgRm9yIHpvb3BsYW5rdG9uCiMgcXEzIDwtIGdncGxvdChmaWx0X2RmX3BjYSwgYWVzKHggPSBwY19zY29yZXMyWywxXSwgeSA9IHBjX3Njb3JlczJbLDJdLCBjb2xvciA9IFg4LmRheS5zZWFzY2FwZXMpKSArCiMgICBnZW9tX3BvaW50KHNpemUgPSA0KSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY3VzdG9tX2NvbG9yc19wY2EpICsKIyAgIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gZWlnZW52ZWN0b3JzWzEsIDFdLCB5ZW5kID0gZWlnZW52ZWN0b3JzWzIsIDFdKSwKIyAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpLCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkIHZlY3RvciBmb3IgUEMxCiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCAyXSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCAyXSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEMyCiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCAzXSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCAzXSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEMzCiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA0XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA0XSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM0CiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA1XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA1XSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM1CiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA2XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA2XSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM2CiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA3XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA3XSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM3CiMgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IGVpZ2VudmVjdG9yc1sxLCA4XSwgeWVuZCA9IGVpZ2VudmVjdG9yc1syLCA4XSksCiMgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSwgY29sb3IgPSAiYmxhY2siKSArICMgQWRkIHZlY3RvciBmb3IgUEM4CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgMV0sIHkgPSBlaWdlbnZlY3RvcnNbMiwgMV0sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzEgKCIsIHBjX3Zhcl9wZXJjZW50WzFdLCAiJTogQWNhbnRoYXJlYSkiLCBzZXAgPSAiIikpLAojICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDMQojICAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDJdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDJdLCAKIyAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZSgiUEMyICgiLCBwY192YXJfcGVyY2VudFsyXSwgIiU6IENvcGVwb2RzKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEMyCiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgM10sIHkgPSBlaWdlbnZlY3RvcnNbMiwgM10sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzMgKCIsIHBjX3Zhcl9wZXJjZW50WzNdLCAiJTogRWNoaW5vZGVybXMpIiwgc2VwID0gIiIpKSwKIyAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJibGFjayIpICsgICMgQWRkIGxhYmVsIGZvciBQQzMKIyAgIGdlb21fdGV4dChhZXMoeCA9IGVpZ2VudmVjdG9yc1sxLCA0XSwgeSA9IGVpZ2VudmVjdG9yc1syLCA0XSwgCiMgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIlBDNCAoIiwgcGNfdmFyX3BlcmNlbnRbNF0sICIlOiBKZWxsaWVzKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM0CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgNV0sIHkgPSBlaWdlbnZlY3RvcnNbMiwgNV0sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzUgKCIsIHBjX3Zhcl9wZXJjZW50WzVdLCAiJTogTGFydmFjZWFucykiLCBzZXAgPSAiIikpLAojICAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKyAgIyBBZGQgbGFiZWwgZm9yIFBDNQojICAgZ2VvbV90ZXh0KGFlcyh4ID0gZWlnZW52ZWN0b3JzWzEsIDZdLCB5ID0gZWlnZW52ZWN0b3JzWzIsIDZdLCAKIyAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZSgiUEM2ICgiLCBwY192YXJfcGVyY2VudFs2XSwgIiU6IFBvbHljaGFldGVzKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM2CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgN10sIHkgPSBlaWdlbnZlY3RvcnNbMiwgN10sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzcgKCIsIHBjX3Zhcl9wZXJjZW50WzddLCAiJTogQ2hhZXRvZ25hdGhzKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM3CiMgICBnZW9tX3RleHQoYWVzKHggPSBlaWdlbnZlY3RvcnNbMSwgOF0sIHkgPSBlaWdlbnZlY3RvcnNbMiwgOF0sIAojICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJQQzggKCIsIHBjX3Zhcl9wZXJjZW50WzhdLCAiJTogUHRlcm9wb2RzKSIsIHNlcCA9ICIiKSksCiMgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBoanVzdCA9IDAuNSwgY29sb3IgPSAiYmxhY2siKSArICAjIEFkZCBsYWJlbCBmb3IgUEM4CiMgICBsYWJzKHggPSAiUEMxIiwgeSA9ICJQQzIiLCBjb2xvciA9ICJYOC5kYXkuc2Vhc2NhcGVzIikgKwojICAgeGxpbSgtMSwgMSkgKwojICAgeWxpbSgtMSwgMSkgKwojICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MikpKSArIAojICAgdGhlbWVfY2xhc3NpYygpICsKIyAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMiksICAjIFNldCBYLWF4aXMgbGFiZWwgZm9udCBzaXplCiMgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSArCiMgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyKSwKIyAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSArCiMgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzIpKSAKIyBxcTMKCmBgYAoKCiMgTWFwIG92ZXJhbGwgV0VJR0hURUQgbWVhbiBjb25jZW50cmF0aW9uIHZhbHVlcyBvZiBzZWxlY3RlZCB0YXhhIGJ5IHRyYW5zZWN0CmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoInN2Z2xpdGUiKQpsaWJyYXJ5KGdnT2NlYW5NYXBzKQpsaWJyYXJ5KGxlYWZsZXQpCiMgbGlicmFyeShwYXRjaHdvcmspCgojIExpc3Qgb2YgY2xhc3MgbmFtZXMKIyBBY2FudGhhcmVhLCBDaGFldG9nbmF0aHMsIE9zdHJhY29kcywgQ29wZXBvZHMsIERlY2Fwb2RzLCBFY2hpbm9kZXJtcywgSmVsbGllcywgTGFydmFjZWFucywgUG9seWNoYWV0cywgUHRlcm9wb2RzCiMgQ2VudHJpYywgQ2VyYXRpdW0sIENoYWV0b2Nlcm9zLCBDaGFpbjIsIENoYWluMywgR3VpbmFyZGlhLCBOZW9jYWx5cHRyZWxsYSwgTm9jdGlsdWNhLCBUcmljaG8Kc2VsZWN0ZWRfY2xhc3MgPC0gIlRyaWNobyIKCiMgRm9yIHpvb3BsYW5rdG9uCnRheGFfbWV0YV9jb25jZW50cmF0aW9uIDwtIHRheGFfbWV0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGFsbF9vZihzZWxlY3RlZF9jbGFzcyksIH4gLiAvIHRvdGFsX3ZvbF9zYW1wbGVkICogMWU2KSkgJT4lCiAgc2VsZWN0KFN0YXRpb24sIGRlY19sYXQsIGRlY19sb24sIHllYXIsIG1vbnRoLCBkYXRlLCB0b3RhbF92b2xfc2FtcGxlZCwgYWxsX29mKHNlbGVjdGVkX2NsYXNzKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh0b3RhbF92b2xfc2FtcGxlZCkpCgojICMgRm9yIHBoeXRvcGxhbmt0b24KIyB0YXhhX21ldGFfY29uY2VudHJhdGlvbiA8LSB0YXhhX21ldGEgJT4lCiMgICBtdXRhdGUoYWNyb3NzKGMoQ2VudHJpYyxDZXJhdGl1bSxDaGFldG9jZXJvcyxDaGFpbjIsQ2hhaW4zLEd1aW5hcmRpYSxOZW9jYWx5cHRyZWxsYSwKIyAgICAgICAgICAgICAgICAgICBOb2N0aWx1Y2EsVHJpY2hvKSwgfiAuL3RvdGFsX3ZvbF9zYW1wbGVkICogMWU2KSkgJT4lCiMgICBzZWxlY3QoU3RhdGlvbiwgZGVjX2xhdCwgZGVjX2xvbiwgeWVhciwgbW9udGgsIGRhdGUsIEF2Zy5jaGwuYS4udWcuTC4sCiMgICAgICAgICAgdGVtcC4uZGVnQy4sIHNhbGluaXR5LHRvdGFsX3ZvbF9zYW1wbGVkLAojICAgICAgICAgIENlbnRyaWMsQ2VyYXRpdW0sQ2hhZXRvY2Vyb3MsQ2hhaW4yLENoYWluMyxHdWluYXJkaWEsTmVvY2FseXB0cmVsbGEsCiMgICAgICAgICAgICAgICAgICAgTm9jdGlsdWNhLFRyaWNobykgJT4lCiMgICBmaWx0ZXIoIWlzLm5hKHRvdGFsX3ZvbF9zYW1wbGVkKSkKCiMgR2V0IHN0YXRpb24gY29vcmRpbmF0ZXMKcGF0aF9zZmVyX2xpc3QgPC0gIn4vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtZW5yaXF1ZW1vbnRlczAxQGdtYWlsLmNvbS9NeSBEcml2ZS9HRHJpdmUvcHJvcG9zYWxzLzIwMjJfMDJfTXVsdGlTdHJlc3Nvcl9OT0FBL21vZHVsZV8xIgpzZmVyX2N1cmF0ZWQgPC0gbGlzdC5maWxlcyhwYXRoX3NmZXJfbGlzdCwgcGF0dGVybiA9ICJzZmVyX3N0YXRpb25zX2N1cmF0ZWQuY3N2IiwgZnVsbC5uYW1lcyA9IFRSVUUpCnNmZXJfc3RhX2xpc3QgPC0gcmVhZC5jc3Yoc2Zlcl9jdXJhdGVkLCBoZWFkZXIgPSBUUlVFKQoKICAgICMgIyBNZXJnZXMgY3VyYXRlZCBzdGF0aW9uIGxpc3Qgd2l0aCB0aGUgY29uY2VudHJhdGlvbiBkZgogICAgY29uY2VudHJhdGlvbl9kZiA8LSB0YXhhX21ldGFfY29uY2VudHJhdGlvbiAlPiUKICAgICAgbGVmdF9qb2luKHNmZXJfc3RhX2xpc3QgJT4lIGZpbHRlcihzdGF0aW9uX2NsYXNzICVpbiUgIkMiKSwgYnkgPSBjKCdTdGF0aW9uJyA9ICdzdGF0aW9uX2lkJykpICU+JQogICAgICBmaWx0ZXIoZ2V0KHNlbGVjdGVkX2NsYXNzKSA+IDApICAjIEV4Y2x1ZGUgcm93cyB3aGVyZSB0aGUgc3BlY2llcyBjb3VudCBpcyB6ZXJvCiAgICAKICAgICMgQ29tcHV0ZSB3ZWlnaHRlZCBhdmVyYWdlIGxhdC9sb25zIGFuZCBtZWFuIHZhcmlhYmxlIHZhbHVlcyBmb3IgdGhlIGN1cnJlbnQgY2xhc3MKICAgIHRheGFfY29uY2VudHJhdGlvbl9hdmcgPC0gY29uY2VudHJhdGlvbl9kZiAlPiUKICAgICAgZ3JvdXBfYnkobGluZV9pZCkgJT4lCiAgICAgIG11dGF0ZSh3ZWlnaHQgPSBnZXQoc2VsZWN0ZWRfY2xhc3MpIC8gc3VtKGdldChzZWxlY3RlZF9jbGFzcyksIG5hLnJtID0gVFJVRSkpICU+JQogICAgICBzdW1tYXJpc2UobG9uZ2l0dWRlID0gd2VpZ2h0ZWQubWVhbihkZWNfbG9uLCB3ID0gd2VpZ2h0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgbGF0aXR1ZGUgPSB3ZWlnaHRlZC5tZWFuKGRlY19sYXQsIHcgPSB3ZWlnaHQsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICBzZWxfdGF4YV9tZWFuID0gbWVhbihnZXQoc2VsZWN0ZWRfY2xhc3MpLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgc2VsX3RheGFfc2QgPSBzZChnZXQoc2VsZWN0ZWRfY2xhc3MpLCBuYS5ybSA9IFRSVUUpKQoKICAgICMgUHJlcGFyZSBkYXRhIGZvciBtYXBwaW5nCiAgICBkdCA8LSBkYXRhLmZyYW1lKAogICAgICBsb24gPSB0YXhhX2NvbmNlbnRyYXRpb25fYXZnJGxvbmdpdHVkZSwgCiAgICAgIGxhdCA9IHRheGFfY29uY2VudHJhdGlvbl9hdmckbGF0aXR1ZGUsIAogICAgICBtZWFuX3BhcmFtID0gdGF4YV9jb25jZW50cmF0aW9uX2F2ZyRzZWxfdGF4YV9tZWFuLAogICAgICBzZF9wYXJhbSA9IHRheGFfY29uY2VudHJhdGlvbl9hdmckc2VsX3RheGFfc2QpICU+JQogICAgbXV0YXRlKHNkX3BhcmFtID0gcmVwbGFjZV9uYShzZF9wYXJhbSwgMCkpCiAgICAKICAgICMgQWRkIHN0YXRpb24gbWFya2VycwogICAgc3RhdGlvbl9tYXJrZXJzIDwtIHNmZXJfc3RhX2xpc3QgJT4lIGZpbHRlcihzdGF0aW9uX2NsYXNzICVpbiUgIkMiKQogICAgCiAgICAjIENyZWF0ZSB0aGUgbWFwCiAgICBjb25jZW50cmF0aW9uX21hcCA8LSBiYXNlbWFwKGxpbWl0cyA9IGMoLTg2LCAtNzkuNSwgMjQsIDI4LjUpLCBiYXRoeW1ldHJ5ID0gVFJVRSkgKwogICAgICAjIGdlb21fcG9pbnQoZGF0YSA9IGR0LCBhZXMoeCA9IGxvbiwgeSA9IGxhdCwgc2l6ZSA9IGxvZzEwKG1lYW5fcGFyYW0rMSksIGNvbG9yID0gbG9nMTAoc2RfcGFyYW0rMSkpKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGR0LCBhZXMoeCA9IGxvbiwgeSA9IGxhdCwgc2l6ZSA9IG1lYW5fcGFyYW0sIGNvbG9yID0gc2RfcGFyYW0pKSArCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIsIG5hLnZhbHVlID0gTkEsIG5hbWUgPSAiU3RhbmRhcmQgRGV2aWF0aW9uIikgKwogICAgICBnZW9tX3BvaW50KGRhdGEgPSBzdGF0aW9uX21hcmtlcnMsIGFlcyh4ID0gbWVhbl9sb24sIHkgPSBtZWFuX2xhdCksIGNvbG9yID0gImJsYWNrIiwgc2hhcGUgPSAzLCBzaXplID0gMS41KSArCiAgICAgIHNjYWxlX3NpemVfY29udGludW91cyhuYW1lID0gIkF2ZXJhZ2UgY29uY2VudHJhdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBicmVha3MgPSBjKDIwMDAsIDQwMDAsIDYwMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKDAsIDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikpKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgZ2d0aXRsZShwYXN0ZShzZWxlY3RlZF9jbGFzcykpCiAgICAgIAogICAgIyBPcHRpb25hbGx5LCBzYXZlIGVhY2ggbWFwIGFzIGFuIGltYWdlCiAgICBnZ3NhdmUocGFzdGUwKCJjb25jX21hcF93ZWlnaHRlZF8iLCBzZWxlY3RlZF9jbGFzcywgIi5wbmciKSwgcGxvdCA9IGNvbmNlbnRyYXRpb25fbWFwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCiAgICBnZ3NhdmUocGFzdGUwKCJjb25jX21hcF93ZWlnaHRlZF8iLCBzZWxlY3RlZF9jbGFzcywgIi5zdmciKSwgcGxvdCA9IGNvbmNlbnRyYXRpb25fbWFwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRldmljZSA9ICJzdmciKQogICAgCiAgICBwcmludChjb25jZW50cmF0aW9uX21hcCkKYGBgCgoKIyBNYXAgb3ZlcmFsbCBtZWFuIGNvbmNlbnRyYXRpb24gdmFsdWVzIG9mIHNlbGVjdGVkIHRheGEgcGVyIHN0YXRpb24KYGBge3J9CiMgTGlzdCBvZiBjbGFzcyBuYW1lcwojIEFjYW50aGFyZWEsIENoYWV0b2duYXRocywgT3N0cmFjb2RzLCBDb3BlcG9kcywgRGVjYXBvZHMsIEVjaGlub2Rlcm1zLCBKZWxsaWVzLCBMYXJ2YWNlYW5zLCBQb2x5Y2hhZXRzLCBQdGVyb3BvZHMsIHBlbGxldHMKIyBDZW50cmljLCBDZXJhdGl1bSwgQ2hhZXRvY2Vyb3MsIENoYWluMiwgQ2hhaW4zLCBHdWluYXJkaWEsIE5lb2NhbHlwdHJlbGxhLCBOb2N0aWx1Y2EsIFRyaWNobwpzZWxlY3RlZF9jbGFzcyA8LSAicGVsbGV0cyIKCnRheGFfbWV0YV9jb25jZW50cmF0aW9uIDwtIHRheGFfbWV0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGFsbF9vZihzZWxlY3RlZF9jbGFzcyksIH4gLiAvIHRvdGFsX3ZvbF9zYW1wbGVkICogMWU2KSkgJT4lCiAgc2VsZWN0KFN0YXRpb24sIGRlY19sYXQsIGRlY19sb24sIHllYXIsIG1vbnRoLCBkYXRlLCB0b3RhbF92b2xfc2FtcGxlZCwgYWxsX29mKHNlbGVjdGVkX2NsYXNzKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh0b3RhbF92b2xfc2FtcGxlZCkpCgojIENvbXB1dGUgbWVhbiBjb25jZW50cmF0aW9uIG9mIHNlbGVjdGVkIGdyb3VwcyBwZXIgc3RhdGlvbgp0YXhhX2NvbmNlbnRyYXRpb25fYXZnX3N0YXRpb24gPC0gdGF4YV9tZXRhX2NvbmNlbnRyYXRpb24gJT4lCiAgZ3JvdXBfYnkoU3RhdGlvbikgJT4lCiAgc3VtbWFyaXNlKGxvbmdpdHVkZV9zdGF0aW9uID0gbWVhbihkZWNfbG9uLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBsYXRpdHVkZV9zdGF0aW9uID0gbWVhbihkZWNfbGF0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzZWxfdGF4YV9tZWFuX3N0YXRpb24gPSBtZWFuKGdldChzZWxlY3RlZF9jbGFzcyksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHNlbF90YXhhX3NkX3N0YXRpb24gPSBzZChnZXQoc2VsZWN0ZWRfY2xhc3MpLCBuYS5ybSA9IFRSVUUpKQoKIyBHZXQgc3RhdGlvbiBjb29yZGluYXRlcwpwYXRoX3NmZXJfbGlzdCA8LSAifi9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1lbnJpcXVlbW9udGVzMDFAZ21haWwuY29tL015IERyaXZlL0dEcml2ZS9wcm9wb3NhbHMvMjAyMl8wMl9NdWx0aVN0cmVzc29yX05PQUEvbW9kdWxlXzEiCnNmZXJfY3VyYXRlZCA8LSBsaXN0LmZpbGVzKHBhdGhfc2Zlcl9saXN0LCBwYXR0ZXJuID0gInNmZXJfc3RhdGlvbnNfY3VyYXRlZC5jc3YiLCBmdWxsLm5hbWVzID0gVFJVRSkKc2Zlcl9zdGFfbGlzdCA8LSByZWFkLmNzdihzZmVyX2N1cmF0ZWQsIGhlYWRlciA9IFRSVUUpCgojICMgTWFwIHdpdGggYmF0aHltZXRyeQogICMgT3ZlcmxheSBjb2xvci1zY2FsZWQgZG90cwpkdF9zdGF0aW9uIDwtIGRhdGEuZnJhbWUoCiAgbG9uX3N0YXRpb24gPSB0YXhhX2NvbmNlbnRyYXRpb25fYXZnX3N0YXRpb24kbG9uZ2l0dWRlX3N0YXRpb24sIAogIGxhdF9zdGF0aW9uID0gdGF4YV9jb25jZW50cmF0aW9uX2F2Z19zdGF0aW9uJGxhdGl0dWRlX3N0YXRpb24sIAogIG1lYW5fcGFyYW1fc3RhdGlvbiA9IHRheGFfY29uY2VudHJhdGlvbl9hdmdfc3RhdGlvbiRzZWxfdGF4YV9tZWFuX3N0YXRpb24sCiAgc2RfcGFyYW1fc3RhdGlvbiA9IHRheGFfY29uY2VudHJhdGlvbl9hdmdfc3RhdGlvbiRzZWxfdGF4YV9zZF9zdGF0aW9uKQoKIyBSZXBsYWNlIE5BIGJ5IHplcm9zCmR0X3N0YXRpb24gPC0gZHRfc3RhdGlvbiAlPiUKICBtdXRhdGUoc2RfcGFyYW1fc3RhdGlvbiA9IHJlcGxhY2VfbmEoc2RfcGFyYW1fc3RhdGlvbiwgMCkpCgojIEFkZCBzdGF0aW9uIG1hcmtlcnMKc3RhdGlvbl9tYXJrZXJzIDwtIHNmZXJfc3RhX2xpc3QgJT4lIGZpbHRlcihzdGF0aW9uX2NsYXNzICVpbiUgIkMiKQogICAgCmNvbmNlbnRyYXRpb25fbWFwX3N0YXRpb24gPC0gYmFzZW1hcChsaW1pdHMgPSBjKC04NiwgLTc5LjUsIDI0LCAyOC41KSwgYmF0aHltZXRyeSA9IFRSVUUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdF9zdGF0aW9uLCBhZXMoeCA9IGxvbl9zdGF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxhdF9zdGF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IG1lYW5fcGFyYW1fc3RhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gc2RfcGFyYW1fc3RhdGlvbikpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAieWVsbG93IiwgaGlnaCA9ICJyZWQiLCBuYS52YWx1ZSA9IE5BLCBuYW1lID0gIlN0YW5kYXJkIERldmlhdGlvbiIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzdGF0aW9uX21hcmtlcnMsIGFlcyh4ID0gbWVhbl9sb24sIHkgPSBtZWFuX2xhdCksIGNvbG9yID0gImJsYWNrIiwgc2hhcGUgPSAzLCBzaXplID0gMS41KSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiQXZlcmFnZSBjb25jZW50cmF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICMgYnJlYWtzID0gYygyNTAsIDUwMCwgNzUwKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKDEsIDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSAid2hpdGUiKSkpICsKICB0aGVtZV9taW5pbWFsKCkgCgojIE9wdGlvbmFsbHksIHNhdmUgZWFjaCBtYXAgYXMgYW4gaW1hZ2UKIyBnZ3NhdmUocGFzdGUwKCJjb25jX21hcF9zdGF0aW9uXyIsIHNlbGVjdGVkX2NsYXNzLCAiLnBuZyIpLCBwbG90ID0gY29uY2VudHJhdGlvbl9tYXBfc3RhdGlvbiwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQpnZ3NhdmUocGFzdGUwKCJjb25jX21hcF9zdGF0aW9uXyIsIHNlbGVjdGVkX2NsYXNzLCAiLnN2ZyIpLCBwbG90ID0gY29uY2VudHJhdGlvbl9tYXBfc3RhdGlvbiwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkZXZpY2UgPSAic3ZnIikKcHJpbnQoY29uY2VudHJhdGlvbl9tYXBfc3RhdGlvbikKCndyaXRlLmNzdihkdF9zdGF0aW9uLCBwYXN0ZTAoImRmXyIsc2VsZWN0ZWRfY2xhc3MsIi5jc3YiKSwgcm93Lm5hbWVzID0gRkFMU0UpCnByaW50KG1heChkdF9zdGF0aW9uJG1lYW5fcGFyYW1fc3RhdGlvbikpCmBgYAoKCiMgTWFwIG1lYW4gY291bnQgdmFsdWVzIG9mIHNlbGVjdGVkIHRheGEgYW5kIHNwZWNpZmllZCBkYXRlcwpgYGB7cn0KIyAjIGdnT2NlYW5NYXBzOgojIGh0dHBzOi8vYmlvc3RhdHMtci5naXRodWIuaW8vYmlvc3RhdHMvd29ya2luZ0luUi8xNDBfbWFwcy5odG1sCiMgaHR0cHM6Ly9naXRodWIuY29tL01pa2tvVmlodGFrYXJpL2dnT2NlYW5NYXBzOiBVc2UgdGhpcyBvbmU6IHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJNaWtrb1ZpaHRha2FyaS9nZ09jZWFuTWFwcyIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dPY2Vhbk1hcHMiKSAjICMgVGhpcyBpcyBvdXRkYXRlZCwgZG9uJ3QgdXNlISEhCmxpYnJhcnkoZ2dPY2Vhbk1hcHMpCmxpYnJhcnkobGVhZmxldCkKCiMgRm9yIE5PQUEgbWFjaGluZXMKIyBwYXRoX3NmZXJfbGlzdCA8LSAiL1VzZXJzL2VucmlxdWUubW9udGVzL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0dvb2dsZURyaXZlLWVucmlxdWVtb250ZXMwMUBnbWFpbC5jb20vTXkgRHJpdmUvR0RyaXZlL3Byb3Bvc2Fscy8yMDIyXzAyX011bHRpU3RyZXNzb3JfTk9BQS9tb2R1bGVfMSIKIyBGb3IgcGVyc29uYWwgbWFjaGluZQpwYXRoX3NmZXJfbGlzdCA8LSAifi9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1lbnJpcXVlbW9udGVzMDFAZ21haWwuY29tL015IERyaXZlL0dEcml2ZS9wcm9wb3NhbHMvMjAyMl8wMl9NdWx0aVN0cmVzc29yX05PQUEvbW9kdWxlXzEiCgpzZmVyX2N1cmF0ZWQgPC0gbGlzdC5maWxlcyhwYXRoX3NmZXJfbGlzdCwgcGF0dGVybiA9ICJzZmVyX3N0YXRpb25zX2N1cmF0ZWQuY3N2IiwgZnVsbC5uYW1lcyA9IFRSVUUpCgpzZmVyX3N0YV9saXN0IDwtIHJlYWQuY3N2KHNmZXJfY3VyYXRlZCwgaGVhZGVyID0gVFJVRSkKCm1lcmdlZF9kYXRhIDwtIHRheGFfbWV0YSAlPiUKICBsZWZ0X2pvaW4oc2Zlcl9zdGFfbGlzdCAlPiUgZmlsdGVyKHN0YXRpb25fY2xhc3MgJWluJSAiQyIpLCBieSA9IGMoJ1N0YXRpb24nID0gJ3N0YXRpb25faWQnKSkKCiMgUmVwbGFjZSAyMDIzIGFuZCAxMCB3aXRoIHlvdXIgc2VsZWN0ZWQgeWVhciBhbmQgbW9udGgKc2VsZWN0ZWRfeWVhciA8LSAyMDIzCnNlbGVjdGVkX21vbnRoIDwtIDExCgojIEZpbHRlciByb3dzCmZpbHRlcmVkX3RheGFfbWV0YSA8LSBtZXJnZWRfZGF0YSAlPiUKICBmaWx0ZXIoeWVhciA9PSBzZWxlY3RlZF95ZWFyLCBtb250aCA9PSBzZWxlY3RlZF9tb250aCkKCiMgZmlsdGVyZWRfdGF4YV9tZXRhIDwtIG1lcmdlZF9kYXRhCgojIENvbXB1dGUgd2VpZ2h0ZWQgYXZlcmFnZSBsYXQgbG9ucyBiYXNlZCBvbiBzZWxlY3RlZCB2YXJpYWJsZSwgYW5kIG1lYW4gdmFyaWFibGUgdmFsdWVzIChlLmcuLCBDb3BlcG9kcykKdGF4YV9hdmcgPC0gZmlsdGVyZWRfdGF4YV9tZXRhICU+JQogIGdyb3VwX2J5KGxpbmVfaWQpICU+JQogIG11dGF0ZSh3ZWlnaHQgPSBHdWluYXJkaWEgLyBzdW0oR3VpbmFyZGlhLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBzdW1tYXJpc2UobG9uZ2l0dWRlID0gd2VpZ2h0ZWQubWVhbihkZWNfbG9uLCB3ID0gd2VpZ2h0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBsYXRpdHVkZSA9IHdlaWdodGVkLm1lYW4oZGVjX2xhdCwgdyA9IHdlaWdodCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2VsX3RheGFfbWVhbiA9IG1lYW4oR3VpbmFyZGlhLCBuYS5ybSA9IFRSVUUpKQoKIyAjIEZpbHRlciBvdXQgdmFsdWVzIGxlc3MgdGhhbiAxCmZpbHRlcmVkX3RheGFfYXZnIDwtIHRheGFfYXZnICU+JQogIGZpbHRlcihzZWxfdGF4YV9tZWFuID4gMCkKCgojIEZpbmQgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWVzIG9mIHNlbF90YXhhX21lYW4KbWluX3ZhbHVlIDwtIG1pbihmaWx0ZXJlZF90YXhhX2F2ZyRzZWxfdGF4YV9tZWFuLCBuYS5ybSA9IFRSVUUpCm1heF92YWx1ZSA8LSBtYXgoZmlsdGVyZWRfdGF4YV9hdmckc2VsX3RheGFfbWVhbiwgbmEucm0gPSBUUlVFKQoKIyAjIEFkanVzdCB0aGUgY29sb3IgcGFsZXR0ZSB3aXRoIHNwZWNpZmllZCB2YWx1ZXMKIyBjb2xvcl9wYWxldHRlIDwtIGNvbG9yTnVtZXJpYyhwYWxldHRlID0gIk9yYW5nZXMiLCBkb21haW4gPSBjKG1pbl92YWx1ZSwgbWF4X3ZhbHVlKSkKCiMgIyBDcmVhdGUgdGhlIG1hcAojIG1hcCA8LSBsZWFmbGV0KGZpbHRlcmVkX3RheGFfYXZnKSAlPiUKIyAgIGFkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRJbWFnZXJ5IikgJT4lCiMgICBhZGRDaXJjbGVNYXJrZXJzKAojICAgICBsbmcgPSB+bG9uZ2l0dWRlLAojICAgICBsYXQgPSB+bGF0aXR1ZGUsCiMgICAgIHJhZGl1cyA9IDEwLAojICAgICBjb2xvciA9IH5jb2xvcl9wYWxldHRlKHNlbF90YXhhX21lYW4pLAojICAgICBmaWxsT3BhY2l0eSA9IDAuOCwKIyAgICAgcG9wdXAgPSB+cGFzdGUoIkxpbmUgSUQ6ICIsIGxpbmVfaWQsICI8YnI+Q29wZXBvZHM6ICIsIHNlbF90YXhhX21lYW4pCiMgICApICU+JQojICAgYWRkTGVnZW5kKAojICAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsCiMgICAgIHBhbCA9IGNvbG9yX3BhbGV0dGUsCiMgICAgIHZhbHVlcyA9IGMobWluX3ZhbHVlLCBtYXhfdmFsdWUpLCAgIyBBZGp1c3RlZCB2YWx1ZXMgaGVyZQojICAgICB0aXRsZSA9ICJDb3BlcG9kIG9jY3VycmVuY2VzIiwKIyAgICAgb3BhY2l0eSA9IDEKIyAgICkKIyBtYXAKCiMgIyBNYXAgd2l0aCBiYXRoeW1ldHJ5CiAgIyBPdmVybGF5IGNvbG9yLXNjYWxlZCBkb3RzCmR0IDwtIGRhdGEuZnJhbWUoCiAgbG9uID0gZmlsdGVyZWRfdGF4YV9hdmckbG9uZ2l0dWRlLCAKICBsYXQgPSBmaWx0ZXJlZF90YXhhX2F2ZyRsYXRpdHVkZSwgCiAgc2VsX3BhcmFtID0gZmlsdGVyZWRfdGF4YV9hdmckc2VsX3RheGFfbWVhbikKCiMgIyBDb2xvcnM6CiMgQWNhbnRoYXJlYSA9IGRhcmt0dXJxdW9pc2U7IGJyZWFrcyA9IGMoMC4yNSwgMSwgMi41LCA1KTsgbGltaXRzID0gYygwLjEsIDEwKQojIENvcGVwb2RzID0gcmVkOyBicmVha3MgPSBjKDAuMjUsIDEsIDIuNSwgNSwgMTApOyBsaW1pdHMgPSBjKDAuMSwgMTUpCiMgQ2hhaW4gZGlhdG9tcyA9IG9yYW5nZTsgYnJlYWtzID0gYygwLjUsIDEsIDEwLCAzMCwgNjApOyBjKDAuMSwgNzApCiMgQ2hhZXRvY2Vyb3MgPSBwdXJwbGU7IGJyZWFrcyA9IGMoMC4yNSwgMSwgMi41LCA1LCAxMCk7IGxpbWl0cyA9IGMoMC4xLCAxNSkKIyBFY2hpbm9kZXJtcyA9IG1hZ2VudGE7IGJyZWFrcyA9IGMoMC41LCAxLCAzLCA1KTsgbGltaXRzID0gYygwLjEsIDUpCiMgTGFydmFjZWFucyA9IHBsdW07IGJyZWFrcyA9IGMoMC41LCAxLCAzLCA1KTsgbGltaXRzID0gYygwLjEsIDUpCiMgUG9seWNoYWV0ZXMgPSBkb2RnZXJibHVlOyBicmVha3MgPSBjKDAuMjUsIDAuNSwgMSwgMyk7IGxpbWl0cyA9IGMoMC4xLCAzKQojIEplbGxpZXMgPSBzbGF0ZWdyYXk0OyBicmVha3MgPSBjKDAuMjUsIDAuNSwgMSwgMik7IGxpbWl0cyA9IGMoMC4xLCAzKQogICAgCm9jY19tYXAgPC0gYmFzZW1hcChsaW1pdHMgPSBjKC04NCwgLTc5LjUsIDI0LCAyOC41KSwgYmF0aHltZXRyeSA9IFRSVUUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdCwgYWVzKHggPSBsb24sIHkgPSBsYXQsIHNpemUgPSBzZWxfcGFyYW0pLCBmaWxsID0gIm9saXZlZHJhYjIiLCBjb2xvciA9ICJvbGl2ZWRyYWIyIikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpbHRlcmVkX3RheGFfbWV0YSwgYWVzKHggPSBkZWNfbG9uLCB5ID0gZGVjX2xhdCksIGNvbG9yID0gImJsYWNrIiwgc2hhcGUgPSAzLCBzaXplID0gMS41KSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiQXZlcmFnZSBjb3VudHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLjUsIDEsIDMsIDUsIDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLjEsIDQwKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKDEsIDE1KSkgKwogIHRoZW1lX21pbmltYWwoKSAKb2NjX21hcAoKIyBvY2NfbWFwX2xlZyA8LSBnZ3Bsb3QoZHQsIGFlcyhsb24sIGxhdCkpICsKIyAgIGdlb21fcG9pbnQoYWVzKHNpemUgPSBzZWxfcGFyYW0pLCBmaWxsID0gImdyZWVuIiwgY29sb3IgPSJncmVlbiIpICsKIyAgIHRoZW1lX21pbmltYWwoKQojIG9jY19tYXBfbGVnCmBgYAoKCiMgQ3JlYXRlIHRpbWUtc2VyaWVzIHBsb3RzIG9mIHNlbGVjdGVkIHRheGEgYXQgc3BlY2lmaWMgc3RhdGlvbnMKYGBge3J9CnNlbGVjdGVkX3ZhcmlhYmxlIDwtICdDaGFldG9jZXJvcycKIyAjIExvd2VyIEtleXMKIyBzZWxlY3RlZF9saW5lX2lkIDwtIGMoJ0xLJywnV1MnLCdNTycsJ0tXJykKIyAjIE1pZGRsZSBLZXlzCiMgc2VsZWN0ZWRfbGluZV9pZCA8LSBjKCdDTycsICdDUicpCiMgIyBPdGhlciByZWdpb25zCnNlbGVjdGVkX2xpbmVfaWQgPC0gYygnQ0FMJykKCiMgRmlsdGVyIHRoZSBkYXRhIGZvciB0aGUgc2VsZWN0ZWQgbGluZV9pZApmaWx0ZXJlZF9tZXJnZWRfZGF0YSA8LSBtZXJnZWRfZGF0YVttZXJnZWRfZGF0YSRsaW5lX2lkICVpbiUgc2VsZWN0ZWRfbGluZV9pZCwgXQojIFJlbW92ZSByb3dzIHdpdGggTkFzIGluIHJlbGV2YW50IGNvbHVtbnMKbW9udGhseV9tZWFucyA8LSBuYS5vbWl0KGZpbHRlcmVkX21lcmdlZF9kYXRhWywgYygiZGF0ZSIsIHNlbGVjdGVkX3ZhcmlhYmxlLCAibGluZV9pZCIpXSkgJT4lCiAgZ3JvdXBfYnkoeWVhcl9tb250aCA9IGZvcm1hdChkYXRlLCAiJVktJW0iKSkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fdmFsdWUgPSBtZWFuKCEhc3ltKHNlbGVjdGVkX3ZhcmlhYmxlKSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgIHNlX3ZhbHVlID0gc2QoISFzeW0oc2VsZWN0ZWRfdmFyaWFibGUpLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpKQoKIyBDcmVhdGUgYSB0aW1lIHNlcmllcyBwbG90CmdncGxvdChtb250aGx5X21lYW5zLCBhZXMoeCA9IHllYXJfbW9udGgsIHkgPSBtZWFuX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIm9yYW5nZSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbl92YWx1ZSAtIHNlX3ZhbHVlLCB5bWF4ID0gbWVhbl92YWx1ZSArIHNlX3ZhbHVlKSwKICAgICAgICAgICAgICAgIHdpZHRoID0gMC4yLCAjIEFkanVzdCB3aWR0aCBhcyBuZWVkZWQKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArICMgQWRqdXN0IHdpZHRoIGFzIG5lZWRlZAogIGxhYnMoeCA9ICJZZWFyLU1vbnRoIiwgeSA9ICJNZWFuIFZhbHVlIikgKwogIGdndGl0bGUoIk1vbnRobHkgTWVhbnMgb2YgU2VsZWN0ZWQgVmFyaWFibGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKCgoKCgoKIyBNYXRjaCBmaWxlIG5hbWUgd2l0aCBzdHJpbmcgSUQgLSBETyBOT1QgVVNFCmBgYHtyfQojIGxpYnJhcnkodGlkeXZlcnNlKQojIGxpYnJhcnkobHVicmlkYXRlKQojIGxpYnJhcnkoZHBseXIpCiMgCiMgIyBleHRyYWN0IHJlbGV2YW50IHBhcnQgb2YgdGhlIHN0cmluZ3MKIyBkZiA8LSByYmluZChjbGFzcy5Db3BlcG9kcywKIyAgICAgICAgICAgICBjbGFzcy5FdWNhbXBpYSwKIyAgICAgICAgICAgICBjbGFzcy5Ob2N0aWx1Y2EsCiMgICAgICAgICAgICAgY2xhc3MuUG9seWNoYWV0cywKIyAgICAgICAgICAgICBjbGFzcy5BY2FudGhhcmVhLAojICAgICAgICAgICAgIGNsYXNzLkNlbnRyaWMsCiMgICAgICAgICAgICAgY2xhc3MuQ2VyYXRpdW0sCiMgICAgICAgICAgICAgY2xhc3MuQ2hhZXRvY2Vyb3MsCiMgICAgICAgICAgICAgY2xhc3MuQ2hhaW4yLAojICAgICAgICAgICAgIGNsYXNzLkNoYWluMywKIyAgICAgICAgICAgICBjbGFzcy5DaGFpbjQsCiMgICAgICAgICAgICAgY2xhc3MuT3N0cmFjb2RzLAojICAgICAgICAgICAgIGNsYXNzLkplbGxpZXMsCiMgICAgICAgICAgICAgY2xhc3MuTGFydmFjZWFucywKIyAgICAgICAgICAgICBjbGFzcy5wZWxsZXRzKQojIHN1Yl9zdHJpbmdzIDwtIHN1YnN0cihkZiRWMSwgc3RhcnQgPSAxMCwgc3RvcCA9IDIyKQojIHVuaXF1ZV9hbGwgPC0gdW5pcXVlKHN1Yl9zdHJpbmdzKQojIAojICMgc2VsZWN0IHVuaXF1ZSBkYXRlcyAodGhpcyBhbGxvd3MgdG8gc2VhcmNoIENURCByZWNvcmRzIHBlciBkYXRlIGFuZCB0aW1lKQojICMgVG8gZmluZCB1bmlxdWUgZGF0ZXMgYW5kIHRpbWVzIHRvIGV4dHJhY3QgQ0RUIGRhdGEgdXNlOiB1bmlxdWVfYWxsW2dyZXBsKCIyMDIyMTIwOSIsIHVuaXF1ZV9hbGwpXQojIAojIGlkX2xpc3QgPC0gdW5pcXVlX2FsbAojIGlkX2xpc3QyICA8LSBhcy5QT1NJWGN0KGlkX2xpc3QsIGZvcm1hdD0iJVklbSVkXyVIJU0iLCB0ej0iVVRDIikKIyAKIyBjb25jX29jY19jb3VudCA8LSBkYXRhLmZyYW1lKGRhdGUgPSBhcy5EYXRlKGNoYXJhY3RlcigpKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQojIAojIGZvciAoIGkgaW4gc2VxX2Fsb25nKGlkX2xpc3QpKXsKIyAgIGFjYW50aGEgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuQWNhbnRoYXJlYSRWMSwgaWRfbGlzdFtpXSkpCiMgICBjZW50cmljIDwtIGFzLmRhdGEuZnJhbWUoc3RyX2NvdW50KGNsYXNzLkNlbnRyaWMkVjEsIGlkX2xpc3RbaV0pKQojICAgY2VyYXRpdW0gPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuQ2VyYXRpdW0kVjEsIGlkX2xpc3RbaV0pKQojICAgY2hhZXRvY2Vyb3MgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuQ2hhZXRvY2Vyb3MkVjEsIGlkX2xpc3RbaV0pKQojICAgY2hhZXRvZyA8LSBhcy5kYXRhLmZyYW1lKHN0cl9jb3VudChjbGFzcy5DaGFldG9nbmF0aHMkVjEsIGlkX2xpc3RbaV0pKQojICAgY2hhaW4yIDwtIGFzLmRhdGEuZnJhbWUoc3RyX2NvdW50KGNsYXNzLkNoYWluMiRWMSwgaWRfbGlzdFtpXSkpCiMgICBjaGFpbjMgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuQ2hhaW4zJFYxLCBpZF9saXN0W2ldKSkKIyAgIGNoYWluNCA8LSBhcy5kYXRhLmZyYW1lKHN0cl9jb3VudChjbGFzcy5DaGFpbjQkVjEsIGlkX2xpc3RbaV0pKQojICAgb3N0cmEgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuT3N0cmFjb2RzJFYxLCBpZF9saXN0W2ldKSkKIyAgIGNvcGVwb2RzIDwtIGFzLmRhdGEuZnJhbWUoc3RyX2NvdW50KGNsYXNzLkNvcGVwb2RzJFYxLCBpZF9saXN0W2ldKSkKIyAgIGRlY2Fwb2QgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuRGVjYXBvZHMkVjEsIGlkX2xpc3RbaV0pKQojICAgZWNoaW5vIDwtIGFzLmRhdGEuZnJhbWUoc3RyX2NvdW50KGNsYXNzLkVjaGlub2Rlcm1zJFYxLCBpZF9saXN0W2ldKSkKIyAgIGV1Y2FtcGlhIDwtIGFzLmRhdGEuZnJhbWUoc3RyX2NvdW50KGNsYXNzLkV1Y2FtcGlhJFYxLCBpZF9saXN0W2ldKSkKIyAgIGplbGxpZXMgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuSmVsbGllcyRWMSwgaWRfbGlzdFtpXSkpCiMgICBsYXJ2YWUgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuTGFydmFjZWFucyRWMSwgaWRfbGlzdFtpXSkpCiMgICBub2N0aSA8LSBhcy5kYXRhLmZyYW1lKHN0cl9jb3VudChjbGFzcy5Ob2N0aWx1Y2EkVjEsIGlkX2xpc3RbaV0pKQojICAgcG9seWNoYWV0ZXMgPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuUG9seWNoYWV0cyRWMSwgaWRfbGlzdFtpXSkpCiMgICB0cmljaG8gPC0gYXMuZGF0YS5mcmFtZShzdHJfY291bnQoY2xhc3MuVHJpY2hvJFYxLCBpZF9saXN0W2ldKSkKIyAKIyAgIEFjYW50aGFyZWEgPC0gY29sU3VtcyhhY2FudGhhICE9IDApCiMgICBDZW50cmljIDwtIGNvbFN1bXMoY2VudHJpYyAhPSAwKQojICAgQ2VyYXRpdW1fc3BwIDwtIGNvbFN1bXMoY2VyYXRpdW0gIT0gMCkKIyAgIENoYWV0b2Nlcm9zIDwtIGNvbFN1bXMoY2hhZXRvY2Vyb3MgIT0gMCkKIyAgIENoYWV0b2duYXRocyA8LSBjb2xTdW1zKGNoYWV0b2cgIT0gMCkKIyAgIERpYXRvbV9jaGFpbnNfMSA8LSBjb2xTdW1zKGNoYWluMiAhPSAwKQojICAgRGlhdG9tX2NoYWluc18yIDwtIGNvbFN1bXMoY2hhaW4zICE9IDApCiMgICBEaWF0b21fY2hhaW5zXzMgPC0gY29sU3VtcyhjaGFpbjQgIT0gMCkKIyAgIE9zdHJhY29kcyA8LSBjb2xTdW1zKG9zdHJhICE9IDApCiMgICBDb3BlcG9kcyA8LSBjb2xTdW1zKGNvcGVwb2RzICE9IDApCiMgICBEZWNhcG9kcyA8LSBjb2xTdW1zKGRlY2Fwb2QgIT0gMCkKIyAgIEVjaGlub2Rlcm1zIDwtIGNvbFN1bXMoZWNoaW5vICE9IDApCiMgICBFdWNhbXBpYV9zcHAgPC0gY29sU3VtcyhldWNhbXBpYSAhPSAwKQojICAgSmVsbGllczwtIGNvbFN1bXMoamVsbGllcyAhPSAwKQojICAgTGFydmFjZWFucyA8LSBjb2xTdW1zKGxhcnZhZSAhPSAwKQojICAgTm9jdGlsdWNhIDwtIGNvbFN1bXMobm9jdGkgIT0gMCkKIyAgIFBvbHljaGFldGVzIDwtIGNvbFN1bXMocG9seWNoYWV0ZXMgIT0gMCkKIyAgIFRyaWNob2Rlc21pdW1fc3BwIDwtIGNvbFN1bXModHJpY2hvICE9IDApCiMgCiMgICAjIFBhcnNlIHRoZSBkYXRlLXRpbWUgc3RyaW5nIHdpdGggeW1kX2htKCkKIyAgIG9jY19kYXRldGltZSAgPC0gYXMuUE9TSVhjdChpZF9saXN0W2ldLCBmb3JtYXQ9IiVZJW0lZF8lSCVNIiwgdHo9IlVUQyIpCiMgICBvY2NfZGF0ZXRpbWVfc3RyIDwtIHN1YnN0cihpZF9saXN0W2ldLCAxLCAxMykKIyAKIyAgIHJvd19kZiA8LSBkYXRhLmZyYW1lKGRhdGUgPSBvY2NfZGF0ZXRpbWUsIG9jY19kYXRldGltZV9zdHIsCiMgICAgICAgICAgICAgICAgICAgICAgICBBY2FudGhhcmVhLAojICAgICAgICAgICAgICAgICAgICAgICAgQ2VudHJpYywKIyAgICAgICAgICAgICAgICAgICAgICAgIENlcmF0aXVtX3NwcCwKIyAgICAgICAgICAgICAgICAgICAgICAgIENoYWV0b2Nlcm9zLAojICAgICAgICAgICAgICAgICAgICAgICAgQ2hhZXRvZ25hdGhzLAojICAgICAgICAgICAgICAgICAgICAgICAgRGlhdG9tX2NoYWluc18xLAojICAgICAgICAgICAgICAgICAgICAgICAgRGlhdG9tX2NoYWluc18yLAojICAgICAgICAgICAgICAgICAgICAgICAgRGlhdG9tX2NoYWluc18zLAojICAgICAgICAgICAgICAgICAgICAgICAgT3N0cmFjb2RzLAojICAgICAgICAgICAgICAgICAgICAgICAgQ29wZXBvZHMsCiMgICAgICAgICAgICAgICAgICAgICAgICBEZWNhcG9kcywKIyAgICAgICAgICAgICAgICAgICAgICAgIEVjaGlub2Rlcm1zLAojICAgICAgICAgICAgICAgICAgICAgICAgRXVjYW1waWFfc3BwLAojICAgICAgICAgICAgICAgICAgICAgICAgSmVsbGllcywKIyAgICAgICAgICAgICAgICAgICAgICAgIExhcnZhY2VhbnMsCiMgICAgICAgICAgICAgICAgICAgICAgICBOb2N0aWx1Y2EsCiMgICAgICAgICAgICAgICAgICAgICAgICBQb2x5Y2hhZXRlcywKIyAgICAgICAgICAgICAgICAgICAgICAgIFRyaWNob2Rlc21pdW1fc3BwCiMgICAgICAgICAgICAgICAgICAgICAgICApCiMgICByb3duYW1lcyhyb3dfZGYpIDwtIGkKIyAKIyAgIGNvbmNfb2NjX2NvdW50IDwtIHJiaW5kKGNvbmNfb2NjX2NvdW50LCByb3dfZGYpCiMgfQojIAojIGNvbmNfb2NjX2ZpbmFsIDwtIGFycmFuZ2UoY29uY19vY2NfY291bnQsIGRhdGUpCgpgYGAKCgojIE1hdGNoIGltYWdlIHJlY29yZHMgd2l0aCBDVEQgbWV0YWRhdGEgYW5kIHNlYXNjYXBlcyAodXNlIHdpdGggc3RyaW5ncyBtYXRjaGluZykgLSBETyBOT1QgVVNFCmBgYHtyfQojICMgRGlyZWN0b3J5IHdoZXJlIHRoZSBDVEQgbWV0YWRhdGEgaXMgbG9jYXRlZAojIGRpcl9wYXRoMiA8LSAifi9lbnJpcXVlbW9udGVzMDFAZ21haWwuY29tIC0gR29vZ2xlIERyaXZlL015IERyaXZlL0dEcml2ZS9PQ0VEX0FPTUwvV1NfY3J1aXNlcy9wbGFua3Rvbl9pbWFnaW5nL0NQSUNTL3dzX2NydWlzZV9jdGQvIgojIGZpbGVfbmFtZSA8LSBsaXN0LmZpbGVzKHBhdGggPSBkaXJfcGF0aDIsIHBhdHRlcm4gPSAiLmNzdiIsIGZ1bGwubmFtZXMgPSBUUlVFKQojIGN0ZF9tZXRhIDwtIHJlYWQuY3N2KGZpbGVfbmFtZSwgZmlsbCA9IFRSVUUpCiMgCiMgZHRfbGlzdCA8LSBjdGRfbWV0YSRHTVQuZGF0ZXRpbWUKIyAKIyBjb25jX2V2ZW50IDwtIGRhdGEuZnJhbWUoKQojIAojIGZvciAoIHQgaW4gc2VxX2Fsb25nKGR0X2xpc3QpKXsKIyAgIGV2ZW50IDwtIHN0cl9jb3VudChjb25jX29jY19maW5hbCRvY2NfZGF0ZXRpbWVfc3RyLCBkdF9saXN0W3RdKQojICAgaWR4X2V2ZW50IDwtIHdoaWNoKGV2ZW50ID09IDEsIGFyci5pbmQgPSBUUlVFKQojICAgb2NjX3JvdyA8LSBjb25jX29jY19maW5hbFtpZHhfZXZlbnQsIF0KIyAgIGV2ZW50X21ldGEgPC0gY3RkX21ldGFbaWR4X2V2ZW50LCBdCiMgICBjb25jX2V2ZW50IDwtIHJiaW5kKGNvbmNfZXZlbnQsIG9jY19yb3cpCiMgfQojIAojIHRheGFfbWV0YSA8LSBjYmluZChjdGRfbWV0YSwgY29uY19ldmVudCkKYGBgCg==